using UnityEngine; using System.Collections; using System.Collections.Generic; using System; using System.Linq; using System.Text; using UnityEngine.Serialization; namespace UnityEngine.ProBuilder { /// /// /// Defines associations between vertex positions that are coincident. The indexes stored in this collection correspond to the ProBuilderMesh.positions array. ///
///
/// Coincident vertices are vertices that despite sharing the same coordinate position, are separate entries in the vertex array. ///
[Serializable] public sealed class SharedVertex : ICollection { /// /// An array of vertex indexes that are coincident. /// [SerializeField] [FormerlySerializedAs("array")] [FormerlySerializedAs("m_Vertexes")] int[] m_Vertices; internal int[] arrayInternal { get { return m_Vertices; } } /// /// Create a new SharedVertex from an int array. /// /// The array to copy. public SharedVertex(IEnumerable indexes) { if (indexes == null) throw new ArgumentNullException("indexes"); m_Vertices = indexes.ToArray(); } /// /// Copy constructor. /// /// The array to copy. public SharedVertex(SharedVertex sharedVertex) { if (sharedVertex == null) throw new ArgumentNullException("sharedVertex"); m_Vertices = new int[sharedVertex.Count]; Array.Copy(sharedVertex.m_Vertices, m_Vertices, m_Vertices.Length); } /// /// Index accessor. /// /// The index to access. public int this[int i] { get { return m_Vertices[i]; } set { m_Vertices[i] = value; } } /// public IEnumerator GetEnumerator() { return ((IEnumerable)m_Vertices).GetEnumerator(); } /// public override string ToString() { return m_Vertices.ToString(","); } /// IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } /// public void Add(int item) { m_Vertices = ArrayUtility.Add(m_Vertices, item); } /// public void Clear() { m_Vertices = new int[0]; } /// public bool Contains(int item) { return Array.IndexOf(m_Vertices, item) > -1; } /// public void CopyTo(int[] array, int arrayIndex) { m_Vertices.CopyTo(array, arrayIndex); } /// public bool Remove(int item) { int ind = Array.IndexOf(m_Vertices, item); if (ind < 0) return false; m_Vertices = m_Vertices.RemoveAt(item); return true; } /// public int Count { get { return m_Vertices.Length; } } /// public bool IsReadOnly { get { return m_Vertices.IsReadOnly; } } /// /// A is used to associate discrete vertices that share a common position. A lookup /// Dictionary provides a fast way to find the index of a in the /// array with a vertex index. /// /// /// A collection of SharedVertex values. /// /// /// A Dictionary where the Key represents an index in the Mesh positions array, and the /// Value is the index of it's placement in the sharedVertices array. /// public static void GetSharedVertexLookup(IList sharedVertices, Dictionary lookup) { lookup.Clear(); for(int i = 0, c = sharedVertices.Count; i < c; i++) { foreach (var index in sharedVertices[i]) { if (!lookup.ContainsKey(index)) lookup.Add(index, i); } } } internal void ShiftIndexes(int offset) { for (int i = 0, c = Count; i < c; i++) m_Vertices[i] += offset; } /// /// Convert a lookup dictionary () back to []. /// /// A Dictionary where Key corresponds to a vertex index, and Value to a common index. /// A new IntArray[] converted from the lookup dictionary. internal static SharedVertex[] ToSharedVertices(IEnumerable> lookup) { if (lookup == null) return new SharedVertex[0]; Dictionary map = new Dictionary(); List> shared = new List>(); foreach (var kvp in lookup) { if (kvp.Value < 0) { shared.Add(new List() { kvp.Key }); } else { int index = -1; if (map.TryGetValue(kvp.Value, out index)) { shared[index].Add(kvp.Key); } else { map.Add(kvp.Value, shared.Count); shared.Add(new List() { kvp.Key }); } } } return ToSharedVertices(shared); } static SharedVertex[] ToSharedVertices(List> list) { if (list == null) throw new ArgumentNullException("list"); SharedVertex[] arr = new SharedVertex[list.Count]; for (int i = 0; i < arr.Length; i++) arr[i] = new SharedVertex(list[i]); return arr; } /// /// Create a new array of SharedVertex objects by comparing points in the passed positions collection. /// /// /// ``` /// ();]]> /// mesh.SetPositions(myNewPositions); /// mesh.SetFaces(myNewFaces); /// mesh.SetSharedIndexes(SharedVertex.GetSharedVerticesWithPositions(myNewPositions)); /// ``` /// /// A collection of Vector3 positions to be tested for equality. /// A new SharedVertex[] where each SharedIndex is a list of indexes that are sharing the same position. public static SharedVertex[] GetSharedVerticesWithPositions(IList positions) { if (positions == null) throw new ArgumentNullException("positions"); Dictionary> sorted = new Dictionary>(); for (int i = 0; i < positions.Count; i++) { List ind; if (sorted.TryGetValue(positions[i], out ind)) ind.Add(i); else sorted.Add(new IntVec3(positions[i]), new List() { i }); } SharedVertex[] share = new SharedVertex[sorted.Count]; int t = 0; foreach (KeyValuePair> kvp in sorted) share[t++] = new SharedVertex(kvp.Value.ToArray()); return share; } internal static SharedVertex[] RemoveAndShift(Dictionary lookup, IEnumerable remove) { var removedVertices = new List(remove); removedVertices.Sort(); return SortedRemoveAndShift(lookup, removedVertices); } internal static SharedVertex[] SortedRemoveAndShift(Dictionary lookup, List remove) { foreach (int i in remove) lookup[i] = -1; var shared = ToSharedVertices(lookup.Where(x => x.Value > -1)); for (int i = 0, c = shared.Length; i < c; i++) { for (int n = 0, l = shared[i].Count; n < l; n++) { int index = ArrayUtility.NearestIndexPriorToValue(remove, shared[i][n]); // add 1 because index is zero based shared[i][n] -= index + 1; } } return shared; } internal static void SetCoincident(ref Dictionary lookup, IEnumerable vertices) { int index = lookup.Count; foreach (var v in vertices) lookup[v] = index; } } }