914 lines
34 KiB
C#
914 lines
34 KiB
C#
|
using System.Collections.Generic;
|
|||
|
using UnityEngine;
|
|||
|
using System;
|
|||
|
|
|||
|
namespace RayFire
|
|||
|
{
|
|||
|
[Serializable]
|
|||
|
public class RFCluster : IComparable<RFCluster>
|
|||
|
{
|
|||
|
/// Main
|
|||
|
public int id;
|
|||
|
public Transform tm;
|
|||
|
public int depth;
|
|||
|
public Vector3 pos;
|
|||
|
public Quaternion rot;
|
|||
|
public Vector3 scl;
|
|||
|
public Bounds bound;
|
|||
|
public bool demolishable;
|
|||
|
public RayfireRigid rigid;
|
|||
|
public List<RFShard> shards;
|
|||
|
public bool cachedHost;
|
|||
|
|
|||
|
/// Collapse
|
|||
|
public float areaCollapse;
|
|||
|
public float minimumArea;
|
|||
|
public float maximumArea;
|
|||
|
public float sizeCollapse;
|
|||
|
public float minimumSize;
|
|||
|
public float maximumSize;
|
|||
|
public int randomCollapse;
|
|||
|
|
|||
|
/// Non Serialized
|
|||
|
[NonSerialized] public bool initialized;
|
|||
|
[NonSerialized] public RFCluster mainCluster;
|
|||
|
[NonSerialized] public List<RFCluster> childClusters;
|
|||
|
[NonSerialized] public List<RFCluster> neibClusters;
|
|||
|
[NonSerialized] public List<float> neibArea;
|
|||
|
[NonSerialized] public List<float> neibPerc;
|
|||
|
|
|||
|
/// Static
|
|||
|
static List<RFShard> checkShards = new List<RFShard>();
|
|||
|
static List<RFShard> newClusterShards = new List<RFShard>();
|
|||
|
|
|||
|
/// /////////////////////////////////////////////////////////
|
|||
|
/// Constructor
|
|||
|
/// /////////////////////////////////////////////////////////
|
|||
|
|
|||
|
// Constructor
|
|||
|
public RFCluster()
|
|||
|
{
|
|||
|
id = -1;
|
|||
|
tm = null;
|
|||
|
depth = 0;
|
|||
|
initialized = false;
|
|||
|
demolishable = true;
|
|||
|
shards = new List<RFShard>();
|
|||
|
rigid = null;
|
|||
|
|
|||
|
// Collapse
|
|||
|
minimumArea = 0;
|
|||
|
maximumArea = 0;
|
|||
|
minimumSize = 0;
|
|||
|
maximumSize = 0;
|
|||
|
randomCollapse = 0;
|
|||
|
cachedHost = false;
|
|||
|
|
|||
|
// Non serialized
|
|||
|
mainCluster = null;
|
|||
|
childClusters = null;
|
|||
|
}
|
|||
|
|
|||
|
// Constructor
|
|||
|
public RFCluster (RFCluster source)
|
|||
|
{
|
|||
|
// Main
|
|||
|
id = source.id;
|
|||
|
tm = source.tm;
|
|||
|
depth = source.depth;
|
|||
|
pos = source.pos;
|
|||
|
rot = source.rot;
|
|||
|
bound = source.bound;
|
|||
|
demolishable = source.demolishable;
|
|||
|
rigid = source.rigid;
|
|||
|
|
|||
|
// Collapse
|
|||
|
areaCollapse = source.areaCollapse;
|
|||
|
minimumArea = source.minimumArea;
|
|||
|
maximumArea = source.maximumArea;
|
|||
|
sizeCollapse = source.sizeCollapse;
|
|||
|
minimumSize = source.minimumSize;
|
|||
|
maximumSize = source.maximumSize;
|
|||
|
randomCollapse = source.randomCollapse;
|
|||
|
|
|||
|
// Remapped shards
|
|||
|
shards = new List<RFShard>(source.shards.Count);
|
|||
|
for (int i = 0; i < source.shards.Count; i++)
|
|||
|
shards.Add (new RFShard (source.shards[i]));
|
|||
|
|
|||
|
// Copy child clusters
|
|||
|
if (source.HasChildClusters == true)
|
|||
|
{
|
|||
|
childClusters = new List<RFCluster>(source.childClusters.Count);
|
|||
|
for (int i = 0; i < source.childClusters.Count; i++)
|
|||
|
childClusters.Add (new RFCluster(source.childClusters[i]));
|
|||
|
}
|
|||
|
|
|||
|
// Set false to reinit it in SaveBackup after all shards will be copied
|
|||
|
initialized = false;
|
|||
|
}
|
|||
|
|
|||
|
// Compare by size
|
|||
|
public int CompareTo(RFCluster otherCluster)
|
|||
|
{
|
|||
|
float thisSize = bound.size.magnitude;
|
|||
|
float otherSize = otherCluster.bound.size.magnitude;
|
|||
|
if (thisSize > otherSize)
|
|||
|
return -1;
|
|||
|
if (thisSize < otherSize)
|
|||
|
return 1;
|
|||
|
return 0;
|
|||
|
}
|
|||
|
|
|||
|
/// /////////////////////////////////////////////////////////
|
|||
|
/// Init Cluster
|
|||
|
/// /////////////////////////////////////////////////////////
|
|||
|
|
|||
|
// Reinit non serialized fields in case of prefab use
|
|||
|
public static void InitCluster (RayfireRigid scr, RFCluster cluster)
|
|||
|
{
|
|||
|
if (cluster.initialized == false)
|
|||
|
{
|
|||
|
// Reinit connected cluster shards non serialized fields
|
|||
|
if (scr.objTp == ObjectType.ConnectedCluster)
|
|||
|
InitConnectedCluster (cluster);
|
|||
|
|
|||
|
// Unfold nested cluster non serialized child clusters
|
|||
|
else if (scr.objTp == ObjectType.NestedCluster)
|
|||
|
InitNestedCluster (scr, cluster);
|
|||
|
|
|||
|
cluster.initialized = true;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
// Init connected cluster
|
|||
|
static void InitConnectedCluster (RFCluster cluster)
|
|||
|
{
|
|||
|
for (int s = 0; s < cluster.shards.Count; s++)
|
|||
|
{
|
|||
|
cluster.shards[s].cluster = cluster;
|
|||
|
cluster.shards[s].neibShards = new List<RFShard>(cluster.shards[s].nIds.Count);
|
|||
|
for (int n = 0; n < cluster.shards[s].nIds.Count; n++)
|
|||
|
cluster.shards[s].neibShards.Add (cluster.shards[cluster.shards[s].nIds[n]]);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
// Unfold nested cluster
|
|||
|
static void InitNestedCluster (RayfireRigid scr, RFCluster cluster)
|
|||
|
{
|
|||
|
// Set shard cluster
|
|||
|
for (int s = 0; s < cluster.shards.Count; s++)
|
|||
|
cluster.shards[s].cluster = cluster;
|
|||
|
|
|||
|
// Check all minor clusters and set main cluster for them
|
|||
|
for (int i = 0; i < scr.clsDemol.minorClusters.Count; i++)
|
|||
|
if (cluster.tm == scr.clsDemol.minorClusters[i].tm.parent)
|
|||
|
scr.clsDemol.minorClusters[i].mainCluster = scr.clsDemol.cluster;
|
|||
|
|
|||
|
// Repeat for child clusters
|
|||
|
if (cluster.HasChildClusters == true)
|
|||
|
for (int i = 0; i < cluster.childClusters.Count; i++)
|
|||
|
InitNestedCluster (scr, cluster.childClusters[i]);
|
|||
|
}
|
|||
|
|
|||
|
/// /////////////////////////////////////////////////////////
|
|||
|
/// Connectivity
|
|||
|
/// /////////////////////////////////////////////////////////
|
|||
|
|
|||
|
// Connectivity check. Separate not connected groups to child clusters
|
|||
|
public static void ConnectivityUnyCheck (RFCluster cluster)
|
|||
|
{
|
|||
|
// Set up child cluster
|
|||
|
if (cluster.childClusters != null)
|
|||
|
cluster.childClusters.Clear();
|
|||
|
|
|||
|
// Not enough shards to check for connectivity
|
|||
|
if (cluster.shards.Count <= 1)
|
|||
|
return;
|
|||
|
|
|||
|
// Check all shards and collect new clusters
|
|||
|
int shardsAmount = cluster.shards.Count;
|
|||
|
|
|||
|
// Set unchecked state
|
|||
|
RFShard.SetUnchecked (cluster.shards);
|
|||
|
|
|||
|
// Check all shards for connectivity but keep uny clusters in main cluster
|
|||
|
for (int s = cluster.shards.Count - 1; s >= 0; s--)
|
|||
|
{
|
|||
|
// Skip checked shards
|
|||
|
if (cluster.shards[s].check == true)
|
|||
|
continue;
|
|||
|
|
|||
|
// Mark as checked
|
|||
|
cluster.shards[s].check = true;
|
|||
|
|
|||
|
// New possible cluster. Create new because applied to cluster
|
|||
|
newClusterShards.Clear();
|
|||
|
newClusterShards.Add (cluster.shards[s]);
|
|||
|
|
|||
|
// Shards in possible connection
|
|||
|
checkShards.Clear();
|
|||
|
checkShards.Add (cluster.shards[s]);
|
|||
|
|
|||
|
// Collect by neibs
|
|||
|
while (checkShards.Count > 0)
|
|||
|
{
|
|||
|
// Add neibs to check If neib among current cluster shards And not already collected
|
|||
|
for (int n = 0; n < checkShards[0].neibShards.Count; n++)
|
|||
|
{
|
|||
|
if (checkShards[0].neibShards[n].check == false)
|
|||
|
{
|
|||
|
// Mark as checked
|
|||
|
checkShards[0].neibShards[n].check = true;
|
|||
|
|
|||
|
// Collect
|
|||
|
checkShards.Add(checkShards[0].neibShards[n]);
|
|||
|
newClusterShards.Add (checkShards[0].neibShards[n]);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
// Remove checked
|
|||
|
checkShards.RemoveAt(0);
|
|||
|
}
|
|||
|
|
|||
|
// Child cluster connected
|
|||
|
if (shardsAmount == newClusterShards.Count)
|
|||
|
break;
|
|||
|
|
|||
|
// Start over if connected shards has uny
|
|||
|
if (RFShard.UnyieldingByShard(newClusterShards) == true)
|
|||
|
continue;
|
|||
|
|
|||
|
// Create new cluster by shards
|
|||
|
NewClusterByShards (cluster, newClusterShards);
|
|||
|
}
|
|||
|
|
|||
|
// Clear
|
|||
|
checkShards.Clear();
|
|||
|
newClusterShards.Clear();
|
|||
|
|
|||
|
// Remove new child clusters shards from original cluster shards list before repeat while cycle
|
|||
|
if (cluster.HasChildClusters == true)
|
|||
|
for (int i = cluster.shards.Count - 1; i >= 0; i--)
|
|||
|
if (cluster.shards[i].cluster != cluster)
|
|||
|
cluster.shards.RemoveAt(i);
|
|||
|
|
|||
|
// Set unchecked state
|
|||
|
RFShard.SetUnchecked (cluster.shards);
|
|||
|
}
|
|||
|
|
|||
|
// Connectivity check
|
|||
|
public static void ConnectivityCheck (RFCluster cluster)
|
|||
|
{
|
|||
|
// Set up child cluster
|
|||
|
if (cluster.childClusters != null)
|
|||
|
cluster.childClusters.Clear();
|
|||
|
|
|||
|
// Not enough shards to check for connectivity
|
|||
|
if (cluster.shards.Count <= 1)
|
|||
|
return;
|
|||
|
|
|||
|
// Set unchecked state
|
|||
|
RFShard.SetUnchecked (cluster.shards);
|
|||
|
|
|||
|
// Check all shards and collect new clusters
|
|||
|
int shardsAmount = cluster.shards.Count;
|
|||
|
|
|||
|
// Iterate through shards and check connectivity
|
|||
|
while (cluster.shards.Count > 0)
|
|||
|
{
|
|||
|
// Lists
|
|||
|
checkShards.Clear();
|
|||
|
checkShards.Add(cluster.shards[0]);
|
|||
|
cluster.shards[0].check = true;
|
|||
|
|
|||
|
// Collect shards for new cluster group
|
|||
|
newClusterShards.Clear();
|
|||
|
newClusterShards.Add (cluster.shards[0]);
|
|||
|
|
|||
|
// Collect by neibs
|
|||
|
while (checkShards.Count > 0)
|
|||
|
{
|
|||
|
// Add neibs to check If neib among current cluster shards And not already collected
|
|||
|
for (int n = 0; n < checkShards[0].neibShards.Count; n++)
|
|||
|
{
|
|||
|
if (checkShards[0].neibShards[n].check == false)
|
|||
|
{
|
|||
|
// Mark as checked
|
|||
|
checkShards[0].neibShards[n].check = true;
|
|||
|
|
|||
|
// Collect
|
|||
|
checkShards.Add(checkShards[0].neibShards[n]);
|
|||
|
newClusterShards.Add(checkShards[0].neibShards[n]);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
// Remove checked
|
|||
|
checkShards.RemoveAt(0);
|
|||
|
}
|
|||
|
|
|||
|
// Child cluster connected
|
|||
|
if (shardsAmount == newClusterShards.Count)
|
|||
|
break;
|
|||
|
|
|||
|
// Create new cluster by shards
|
|||
|
NewClusterByShards (cluster, newClusterShards);
|
|||
|
|
|||
|
// Remove new cluster shards from original cluster shards list before repeat while cycle
|
|||
|
for (int i = cluster.shards.Count - 1; i >= 0; i--)
|
|||
|
if (cluster.shards[i].cluster != cluster)
|
|||
|
cluster.shards.RemoveAt(i);
|
|||
|
}
|
|||
|
|
|||
|
// Clear
|
|||
|
checkShards.Clear();
|
|||
|
newClusterShards.Clear();
|
|||
|
|
|||
|
// Set unchecked state
|
|||
|
RFShard.SetUnchecked (cluster.shards);
|
|||
|
}
|
|||
|
|
|||
|
// Create new cluster by shards, set id and main cluster link
|
|||
|
public static void NewClusterByShards(RFCluster mainCLuster, List<RFShard> shards)
|
|||
|
{
|
|||
|
// Child cluster not connected. Create new cluster and add to parent
|
|||
|
RFCluster newCluster = new RFCluster();
|
|||
|
for (int i = 0; i < shards.Count; i++)
|
|||
|
newCluster.shards.Add (shards[i]);
|
|||
|
|
|||
|
newCluster.demolishable = mainCLuster.demolishable;
|
|||
|
|
|||
|
// Set main cluster
|
|||
|
if (mainCLuster.mainCluster == null)
|
|||
|
newCluster.mainCluster = mainCLuster;
|
|||
|
else
|
|||
|
newCluster.mainCluster = mainCLuster.mainCluster;
|
|||
|
|
|||
|
// Set uniq id after main cluster defined
|
|||
|
newCluster.id = GetUniqClusterId (newCluster);
|
|||
|
|
|||
|
// Set shards cluster to new cluster
|
|||
|
for (int i = 0; i < newCluster.shards.Count; i++)
|
|||
|
newCluster.shards[i].cluster = newCluster;
|
|||
|
|
|||
|
// Add new child cluster
|
|||
|
mainCLuster.AddChildCluster (newCluster);
|
|||
|
}
|
|||
|
|
|||
|
// Add new child cluster
|
|||
|
public void AddChildCluster(RFCluster cluster)
|
|||
|
{
|
|||
|
if (childClusters == null)
|
|||
|
childClusters = new List<RFCluster>();
|
|||
|
childClusters.Add(cluster);
|
|||
|
}
|
|||
|
|
|||
|
// Set biggest child cluster shards to original cluster. Cant be 1 child cluster
|
|||
|
public static void ReduceChildClusters (RFCluster cluster)
|
|||
|
{
|
|||
|
// Cluster has child cluster
|
|||
|
if (cluster.childClusters != null && cluster.childClusters.Count > 0)
|
|||
|
{
|
|||
|
// Get biggest cluster
|
|||
|
int biggestInd = GetBiggestCluster (cluster.childClusters);
|
|||
|
|
|||
|
// Set biggest cluster shards to original cluster shards to reuse it
|
|||
|
cluster.shards = cluster.childClusters[biggestInd].shards;
|
|||
|
|
|||
|
// Set shards cluster back to original cluster
|
|||
|
for (int i = 0; i < cluster.shards.Count; i++)
|
|||
|
cluster.shards[i].cluster = cluster;
|
|||
|
|
|||
|
// Remove biggest cluster from child clusters
|
|||
|
cluster.childClusters.RemoveAt (biggestInd);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/// /////////////////////////////////////////////////////////
|
|||
|
/// Bounds
|
|||
|
/// /////////////////////////////////////////////////////////
|
|||
|
|
|||
|
// Get all children bounds
|
|||
|
public static Bounds GetChildrenBound(Transform tm)
|
|||
|
{
|
|||
|
// Collect all children transforms
|
|||
|
Renderer[] renderers = tm.GetComponentsInChildren<Renderer>();
|
|||
|
|
|||
|
// Get list of bounds
|
|||
|
Bounds[] bounds = new Bounds[renderers.Length];
|
|||
|
for (int i = 0; i < renderers.Length; i++)
|
|||
|
bounds[i] = renderers[i].bounds;
|
|||
|
return GetBoundsBound(bounds);
|
|||
|
}
|
|||
|
|
|||
|
// Get all children bounds
|
|||
|
public static Bounds GetClusterBound(RFCluster cluster)
|
|||
|
{
|
|||
|
// Get list of bounds
|
|||
|
Bounds[] bounds = new Bounds[cluster.shards.Count + cluster.childClusters.Count];
|
|||
|
for (int i = 0; i < cluster.shards.Count; i++)
|
|||
|
bounds[i] = cluster.shards[i].bnd;
|
|||
|
for (int i = 0; i < cluster.childClusters.Count; i++)
|
|||
|
bounds[i + cluster.shards.Count] = cluster.childClusters[i].bound;
|
|||
|
|
|||
|
return GetBoundsBound(bounds);
|
|||
|
}
|
|||
|
|
|||
|
// Get bound by list of bounds
|
|||
|
public static Bounds GetBoundsBound(Bounds[] bounds)
|
|||
|
{
|
|||
|
// new bound
|
|||
|
Bounds bound = new Bounds();
|
|||
|
|
|||
|
// No mesh renderers
|
|||
|
if (bounds.Length == 0)
|
|||
|
{
|
|||
|
Debug.Log("GetBoundsBound warning");
|
|||
|
return bound;
|
|||
|
}
|
|||
|
|
|||
|
// Basic bounds min and max values
|
|||
|
float minX = bounds[0].min.x;
|
|||
|
float minY = bounds[0].min.y;
|
|||
|
float minZ = bounds[0].min.z;
|
|||
|
float maxX = bounds[0].max.x;
|
|||
|
float maxY = bounds[0].max.y;
|
|||
|
float maxZ = bounds[0].max.z;
|
|||
|
|
|||
|
// Compare with other bounds
|
|||
|
if (bounds.Length > 1)
|
|||
|
{
|
|||
|
for (int i = 1; i < bounds.Length; i++)
|
|||
|
{
|
|||
|
if (bounds[i].min.x < minX) minX = bounds[i].min.x;
|
|||
|
if (bounds[i].min.y < minY) minY = bounds[i].min.y;
|
|||
|
if (bounds[i].min.z < minZ) minZ = bounds[i].min.z;
|
|||
|
if (bounds[i].max.x > maxX) maxX = bounds[i].max.x;
|
|||
|
if (bounds[i].max.y > maxY) maxY = bounds[i].max.y;
|
|||
|
if (bounds[i].max.z > maxZ) maxZ = bounds[i].max.z;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
// Get center
|
|||
|
bound.center = new Vector3((maxX - minX) / 2f, (maxY - minY) / 2f, (maxZ - minZ) / 2f);
|
|||
|
|
|||
|
// Get min and max vectors
|
|||
|
bound.min = new Vector3(minX, minY, minZ);
|
|||
|
bound.max = new Vector3(maxX, maxY, maxZ);
|
|||
|
|
|||
|
return bound;
|
|||
|
}
|
|||
|
|
|||
|
// Get bound by list of bounds
|
|||
|
public static Bounds GetShardsBound(List<RFShard> shards)
|
|||
|
{
|
|||
|
// new bound
|
|||
|
Bounds bound = new Bounds();
|
|||
|
|
|||
|
// No mesh renderers
|
|||
|
if (shards.Count == 0)
|
|||
|
{
|
|||
|
Debug.Log("GetShardsBound warning");
|
|||
|
return bound;
|
|||
|
}
|
|||
|
|
|||
|
// Basic bounds min and max values
|
|||
|
float minX = shards[0].bnd.min.x;
|
|||
|
float minY = shards[0].bnd.min.y;
|
|||
|
float minZ = shards[0].bnd.min.z;
|
|||
|
float maxX = shards[0].bnd.max.x;
|
|||
|
float maxY = shards[0].bnd.max.y;
|
|||
|
float maxZ = shards[0].bnd.max.z;
|
|||
|
|
|||
|
// Compare with other bounds
|
|||
|
if (shards.Count > 1)
|
|||
|
{
|
|||
|
for (int i = 1; i < shards.Count; i++)
|
|||
|
{
|
|||
|
if (shards[i].bnd.min.x < minX) minX = shards[i].bnd.min.x;
|
|||
|
if (shards[i].bnd.min.y < minY) minY = shards[i].bnd.min.y;
|
|||
|
if (shards[i].bnd.min.z < minZ) minZ = shards[i].bnd.min.z;
|
|||
|
if (shards[i].bnd.max.x > maxX) maxX = shards[i].bnd.max.x;
|
|||
|
if (shards[i].bnd.max.y > maxY) maxY = shards[i].bnd.max.y;
|
|||
|
if (shards[i].bnd.max.z > maxZ) maxZ = shards[i].bnd.max.z;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
// Get center
|
|||
|
bound.center = new Vector3((maxX - minX) / 2f, (maxY - minY) / 2f, (maxZ - minZ) / 2f);
|
|||
|
|
|||
|
// Get min and max vectors
|
|||
|
bound.min = new Vector3(minX, minY, minZ);
|
|||
|
bound.max = new Vector3(maxX, maxY, maxZ);
|
|||
|
|
|||
|
return bound;
|
|||
|
}
|
|||
|
|
|||
|
// Get bound by list of bounds
|
|||
|
public static Bounds GetShardsBoundByPosition(List<RFShard> shards)
|
|||
|
{
|
|||
|
// new bound
|
|||
|
Bounds bound = new Bounds();
|
|||
|
|
|||
|
// No mesh renderers
|
|||
|
if (shards.Count == 0)
|
|||
|
{
|
|||
|
Debug.Log("GetShardsBoundByPosition warning");
|
|||
|
return bound;
|
|||
|
}
|
|||
|
|
|||
|
// Get all position lists
|
|||
|
List<Vector3> posList = new List<Vector3>(shards.Count);
|
|||
|
for (int i = 0; i < shards.Count; i++)
|
|||
|
posList.Add (shards[i].tm.position);
|
|||
|
|
|||
|
|
|||
|
// Basic bounds min and max values
|
|||
|
float minX = shards[0].tm.position.x - 0.01f;
|
|||
|
float minY = shards[0].tm.position.y - 0.01f;
|
|||
|
float minZ = shards[0].tm.position.z - 0.01f;
|
|||
|
float maxX = shards[0].tm.position.x + 0.01f;
|
|||
|
float maxY = shards[0].tm.position.y + 0.01f;
|
|||
|
float maxZ = shards[0].tm.position.z + 0.01f;
|
|||
|
|
|||
|
// Compare with other bounds
|
|||
|
if (shards.Count > 1)
|
|||
|
{
|
|||
|
for (int i = 1; i < posList.Count; i++)
|
|||
|
{
|
|||
|
if (posList[i].x < minX) minX = posList[i].x;
|
|||
|
if (posList[i].y < minY) minY = posList[i].y;
|
|||
|
if (posList[i].z < minZ) minZ = posList[i].z;
|
|||
|
if (posList[i].x > maxX) maxX = posList[i].x;
|
|||
|
if (posList[i].y > maxY) maxY = posList[i].y;
|
|||
|
if (posList[i].z > maxZ) maxZ = posList[i].z;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
// Get center
|
|||
|
bound.center = new Vector3((maxX - minX) / 2f, (maxY - minY) / 2f, (maxZ - minZ) / 2f);
|
|||
|
|
|||
|
// Get min and max vectors
|
|||
|
bound.min = new Vector3(minX, minY, minZ);
|
|||
|
bound.max = new Vector3(maxX, maxY, maxZ);
|
|||
|
|
|||
|
return bound;
|
|||
|
}
|
|||
|
|
|||
|
/// /////////////////////////////////////////////////////////
|
|||
|
/// Static
|
|||
|
/// /////////////////////////////////////////////////////////
|
|||
|
|
|||
|
// Get biggest cluster
|
|||
|
static int GetBiggestCluster(List<RFCluster> clusters)
|
|||
|
{
|
|||
|
// Only one cluster
|
|||
|
if (clusters.Count == 1)
|
|||
|
return 0;
|
|||
|
|
|||
|
int index = 0;
|
|||
|
int amount = 0;
|
|||
|
for (int i = 0; i < clusters.Count; i++)
|
|||
|
{
|
|||
|
if (clusters[i].shards.Count > amount)
|
|||
|
{
|
|||
|
amount = clusters[i].shards.Count;
|
|||
|
index = i;
|
|||
|
}
|
|||
|
}
|
|||
|
return index;
|
|||
|
}
|
|||
|
|
|||
|
// Collect solo shards, remove from cluster, reinit cluster
|
|||
|
public static void DetachSoloShards(RFCluster cluster, List<RFShard> soloShards)
|
|||
|
{
|
|||
|
for (int s = cluster.shards.Count - 1; s >= 0; s--)
|
|||
|
if (cluster.shards[s].neibShards.Count == 0)
|
|||
|
{
|
|||
|
soloShards.Add (cluster.shards[s]);
|
|||
|
cluster.shards[s].cluster = null;
|
|||
|
cluster.shards.RemoveAt (s);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
// Set uniq id after main cluster defined
|
|||
|
public static int GetUniqClusterId (RFCluster cluster)
|
|||
|
{
|
|||
|
// Main cluster is
|
|||
|
if (cluster.mainCluster == null)
|
|||
|
return 1;
|
|||
|
|
|||
|
if (cluster.mainCluster.rigid == null)
|
|||
|
return 2;
|
|||
|
|
|||
|
cluster.mainCluster.rigid.clsDemol.clsCount++;
|
|||
|
return cluster.mainCluster.rigid.clsDemol.clsCount;
|
|||
|
}
|
|||
|
|
|||
|
// Integrity check
|
|||
|
public static bool IntegrityCheck(RFCluster cluster)
|
|||
|
{
|
|||
|
if (cluster != null && cluster.shards.Count > 0)
|
|||
|
for (int i = 0; i < cluster.shards.Count; i++)
|
|||
|
if (cluster.shards[i].tm == null)
|
|||
|
return false;
|
|||
|
return true;
|
|||
|
}
|
|||
|
|
|||
|
// Create Root for Cluster
|
|||
|
public static void CreateClusterRoot(RFCluster cluster, Vector3 pos, Quaternion rot, int layer, string tag, string nm)
|
|||
|
{
|
|||
|
GameObject leftRoot = new GameObject(nm);
|
|||
|
cluster.tm = leftRoot.transform;
|
|||
|
cluster.tm.position = pos;
|
|||
|
cluster.tm.rotation = rot;
|
|||
|
leftRoot.layer = layer;
|
|||
|
leftRoot.tag = tag;
|
|||
|
}
|
|||
|
|
|||
|
// Get mass by cluster shards mass
|
|||
|
public static float GetClusterMass (RFCluster cluster)
|
|||
|
{
|
|||
|
float m = 0;
|
|||
|
for (int s = 0; s < cluster.shards.Count; s++)
|
|||
|
if (cluster.shards[s].rb != null)
|
|||
|
m += cluster.shards[s].rb.mass;
|
|||
|
return m;
|
|||
|
}
|
|||
|
|
|||
|
/// /////////////////////////////////////////////////////////
|
|||
|
/// Getters
|
|||
|
/// /////////////////////////////////////////////////////////
|
|||
|
|
|||
|
// Had child cluster
|
|||
|
public bool HasChildClusters { get { return childClusters != null && childClusters.Count > 0; } }
|
|||
|
|
|||
|
// Check if cluster has unyielding shards
|
|||
|
public bool UnyieldingByShard { get {
|
|||
|
for (int i = 0; i < shards.Count; i++)
|
|||
|
if (shards[i].uny == true)
|
|||
|
return true;
|
|||
|
return false; } }
|
|||
|
|
|||
|
// Check if cluster has unyielding shards
|
|||
|
public bool UnyieldingByRigid { get {
|
|||
|
for (int i = 0; i < shards.Count; i++)
|
|||
|
if (shards[i].rigid.activation.uny == true)
|
|||
|
return true;
|
|||
|
return false; } }
|
|||
|
|
|||
|
// Check if cluster has unyielding shards and return its sim state
|
|||
|
public SimType UnyieldingSimByShard { get {
|
|||
|
for (int i = 0; i < shards.Count; i++)
|
|||
|
if (shards[i].uny == true)
|
|||
|
return shards[i].sm;
|
|||
|
return SimType.Sleeping; } }
|
|||
|
|
|||
|
/// /////////////////////////////////////////////////////////
|
|||
|
/// Cluster component
|
|||
|
/// /////////////////////////////////////////////////////////
|
|||
|
|
|||
|
// Get all shards ain all child clusters
|
|||
|
List<RFShard> GetNestedShards(bool OwnShards = false)
|
|||
|
{
|
|||
|
List<RFShard> nestedShards = new List<RFShard>();
|
|||
|
List<RFCluster> nestedClusters = new List<RFCluster>();
|
|||
|
nestedClusters.AddRange(childClusters);
|
|||
|
|
|||
|
// Collect own shards
|
|||
|
if (OwnShards == true)
|
|||
|
nestedShards.AddRange(shards);
|
|||
|
|
|||
|
while (nestedClusters.Count > 0)
|
|||
|
{
|
|||
|
nestedShards.AddRange(nestedClusters[0].shards);
|
|||
|
nestedClusters.AddRange(nestedClusters[0].childClusters);
|
|||
|
nestedClusters.RemoveAt(0);
|
|||
|
}
|
|||
|
return nestedShards;
|
|||
|
}
|
|||
|
|
|||
|
// Get all shards ain all child clusters
|
|||
|
List<RFCluster> GetNestedClusters()
|
|||
|
{
|
|||
|
List<RFCluster> nestedClusters = new List<RFCluster>();
|
|||
|
nestedClusters.AddRange(childClusters);
|
|||
|
|
|||
|
List<RFCluster> checkClusters = new List<RFCluster>();
|
|||
|
checkClusters.AddRange(childClusters);
|
|||
|
|
|||
|
while (checkClusters.Count > 0)
|
|||
|
{
|
|||
|
nestedClusters.AddRange(checkClusters[0].childClusters);
|
|||
|
checkClusters.RemoveAt(0);
|
|||
|
}
|
|||
|
|
|||
|
return nestedClusters;
|
|||
|
}
|
|||
|
|
|||
|
// Check if other cluster has shared face
|
|||
|
bool TrisNeib(RFCluster otherCluster)
|
|||
|
{
|
|||
|
// Check if cluster shards has 1 neib in other cluster shards
|
|||
|
foreach (RFShard shard in shards)
|
|||
|
for (int i = 0; i < shard.neibShards.Count; i++)
|
|||
|
if (otherCluster.shards.Contains(shard.neibShards[i]) == true)
|
|||
|
return true;
|
|||
|
|
|||
|
List<RFShard> nestedShards = GetNestedShards();
|
|||
|
List<RFShard> otherNestedShards = otherCluster.GetNestedShards();
|
|||
|
|
|||
|
foreach (RFShard shard in nestedShards)
|
|||
|
for (int i = 0; i < shard.neibShards.Count; i++)
|
|||
|
if (otherNestedShards.Contains(shard.neibShards[i]) == true)
|
|||
|
return true;
|
|||
|
|
|||
|
//// Check if other cluster among neib clusters
|
|||
|
//if (neibClusters.Contains(otherCluster) == true)
|
|||
|
// return true;
|
|||
|
|
|||
|
//// Check if other cluster children clusters has
|
|||
|
//foreach (RFCluster cluster in childClusters)
|
|||
|
// for (int i = 0; i < cluster.neibClusters.Count; i++)
|
|||
|
// if (otherCluster.neibClusters.Contains(cluster.neibClusters[i]) == true)
|
|||
|
// return true;
|
|||
|
|
|||
|
return false;
|
|||
|
}
|
|||
|
|
|||
|
// Get shared area with another cluster
|
|||
|
float NeibArea(RFCluster otherCluster)
|
|||
|
{
|
|||
|
float area = 0f;
|
|||
|
foreach (RFShard shard in shards)
|
|||
|
for (int i = 0; i < shard.neibShards.Count; i++)
|
|||
|
if (otherCluster.shards.Contains(shard.neibShards[i]) == true)
|
|||
|
area += shard.nArea[i];
|
|||
|
|
|||
|
|
|||
|
List<RFShard> nestedShards = GetNestedShards();
|
|||
|
List<RFShard> otherNestedShards = otherCluster.GetNestedShards();
|
|||
|
|
|||
|
foreach (RFShard shard in nestedShards)
|
|||
|
for (int i = 0; i < shard.neibShards.Count; i++)
|
|||
|
if (otherNestedShards.Contains(shard.neibShards[i]) == true)
|
|||
|
area += shard.nArea[i];
|
|||
|
|
|||
|
|
|||
|
//// Check if other cluster children clusters has
|
|||
|
//foreach (RFCluster cluster in childClusters)
|
|||
|
// for (int i = 0; i < cluster.neibClusters.Count; i++)
|
|||
|
// if (otherCluster.neibClusters.Contains(cluster.neibClusters[i]) == true)
|
|||
|
// area += cluster.neibArea[i];
|
|||
|
|
|||
|
return area;
|
|||
|
}
|
|||
|
|
|||
|
// Get neib index with biggest shared area
|
|||
|
public int GetNeibIndArea(List<RFCluster> clusterList = null)
|
|||
|
{
|
|||
|
// Get neib index with biggest shared area
|
|||
|
float biggestArea = 0f;
|
|||
|
int neibInd = 0;
|
|||
|
for (int i = 0; i < neibClusters.Count; i++)
|
|||
|
{
|
|||
|
// Skip if check neib shard not in filter list
|
|||
|
if (clusterList != null)
|
|||
|
if (clusterList.Contains(neibClusters[i]) == false)
|
|||
|
continue;
|
|||
|
|
|||
|
// Remember if bigger
|
|||
|
if (neibArea[i] > biggestArea)
|
|||
|
{
|
|||
|
biggestArea = neibArea[i];
|
|||
|
neibInd = i;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
// Return index of neib with biggest shared area
|
|||
|
if (biggestArea > 0)
|
|||
|
return neibInd;
|
|||
|
|
|||
|
// No neib
|
|||
|
return -1;
|
|||
|
}
|
|||
|
|
|||
|
// Find neib clusters amount cluster list and set them with neib area
|
|||
|
public static void SetClusterNeib(List<RFCluster> clusters, bool connectivity)
|
|||
|
{
|
|||
|
// Set list
|
|||
|
foreach (RFCluster cluster in clusters)
|
|||
|
{
|
|||
|
cluster.neibClusters = new List<RFCluster>();
|
|||
|
cluster.neibArea = new List<float>();
|
|||
|
cluster.neibPerc = new List<float>();
|
|||
|
}
|
|||
|
|
|||
|
// Set neib and area info
|
|||
|
for (int i = 0; i < clusters.Count; i++)
|
|||
|
{
|
|||
|
for (int s = 0; s < clusters.Count; s++)
|
|||
|
{
|
|||
|
if (s != i)
|
|||
|
{
|
|||
|
// Check if shard was not added as neib before
|
|||
|
if (clusters[s].neibClusters.Contains(clusters[i]) == false)
|
|||
|
{
|
|||
|
// Bounding box intersection check
|
|||
|
if (clusters[i].bound.Intersects(clusters[s].bound) == true)
|
|||
|
{
|
|||
|
// No need in face check connectivity
|
|||
|
if (connectivity == false)
|
|||
|
{
|
|||
|
float size = clusters[i].bound.size.magnitude;
|
|||
|
|
|||
|
clusters[i].neibClusters.Add(clusters[s]);
|
|||
|
clusters[i].neibArea.Add(size);
|
|||
|
|
|||
|
clusters[s].neibClusters.Add(clusters[i]);
|
|||
|
clusters[s].neibArea.Add(size);
|
|||
|
}
|
|||
|
|
|||
|
// Face to face connectivity check
|
|||
|
else
|
|||
|
{
|
|||
|
// Check for shared faces and collect neibs and areas
|
|||
|
if (clusters[i].TrisNeib(clusters[s]) == true)
|
|||
|
{
|
|||
|
float area = clusters[i].NeibArea(clusters[s]);
|
|||
|
|
|||
|
clusters[i].neibClusters.Add(clusters[s]);
|
|||
|
clusters[i].neibArea.Add(area);
|
|||
|
|
|||
|
clusters[s].neibClusters.Add(clusters[i]);
|
|||
|
clusters[s].neibArea.Add(area);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
// Set area ratio
|
|||
|
float maxArea = Mathf.Max(clusters[i].neibArea.ToArray());
|
|||
|
foreach (float area in clusters[i].neibArea)
|
|||
|
{
|
|||
|
if (maxArea > 0)
|
|||
|
clusters[i].neibPerc.Add(area / maxArea);
|
|||
|
else
|
|||
|
clusters[i].neibPerc.Add(0f);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
// Get neib cluster from shardList which is neib to one of the shards
|
|||
|
public static RFCluster GetNeibClusterArea(List<RFCluster> clusters, List<RFCluster> clusterList)
|
|||
|
{
|
|||
|
// No clusters to pick
|
|||
|
if (clusterList.Count == 0)
|
|||
|
return null;
|
|||
|
|
|||
|
// Get all neibs for clusters, exclude neibs not from clusterList
|
|||
|
List<RFCluster> allNeibs = new List<RFCluster>();
|
|||
|
|
|||
|
// Biggest area
|
|||
|
float biggestArea = 0f;
|
|||
|
RFCluster biggestCluster = null;
|
|||
|
|
|||
|
// Check cluster
|
|||
|
foreach (RFCluster cluster in clusters)
|
|||
|
{
|
|||
|
// Check neibs
|
|||
|
for (int i = 0; i < cluster.neibClusters.Count; i++)
|
|||
|
{
|
|||
|
// Shared are is too small relative other neibs
|
|||
|
if (cluster.neibPerc[i] < 0.5f)
|
|||
|
continue;
|
|||
|
|
|||
|
// Neib cluster has shared area lower than already founded
|
|||
|
if (biggestArea >= cluster.neibArea[i])
|
|||
|
continue;
|
|||
|
|
|||
|
// Neib already in neib list
|
|||
|
if (allNeibs.Contains(cluster.neibClusters[i]) == true)
|
|||
|
continue;
|
|||
|
|
|||
|
// Neib not among allowed clusters
|
|||
|
if (clusterList.Contains(cluster.neibClusters[i]) == false)
|
|||
|
continue;
|
|||
|
|
|||
|
// Remember neib
|
|||
|
allNeibs.Add(cluster.neibClusters[i]);
|
|||
|
biggestArea = cluster.neibArea[i];
|
|||
|
biggestCluster = cluster.neibClusters[i];
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
// Pick shard with biggest area
|
|||
|
return biggestCluster;
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
}
|
|||
|
|