Exemple #1
0
        /// <summary>
        /// Insert a new vertex at the center of a face and connect the center of all edges to it.
        /// </summary>
        /// <param name="face"></param>
        /// <param name="edges"></param>
        /// <param name="vertices"></param>
        /// <returns></returns>
        static List <ConnectFaceRebuildData> ConnectEdgesInFace(
            Face face,
            List <WingedEdge> edges,
            List <Vertex> vertices)
        {
            List <Edge> perimeter  = WingedEdge.SortEdgesByAdjacency(face);
            int         splitCount = edges.Count;

            Vertex centroid = Vertex.Average(vertices, face.distinctIndexesInternal);

            List <List <Vertex> > n_vertices = ArrayUtility.Fill <List <Vertex> >(x => { return(new List <Vertex>()); }, splitCount);
            List <List <int> >    n_indexes  = ArrayUtility.Fill <List <int> >(x => { return(new List <int>()); }, splitCount);

            HashSet <Edge> edgesToSplit = new HashSet <Edge>(edges.Select(x => x.edge.local));

            int index = 0;

            // creates two new polygon perimeter lines by stepping the current face perimeter and inserting new vertices where edges match
            for (int i = 0; i < perimeter.Count; i++)
            {
                n_vertices[index % splitCount].Add(vertices[perimeter[i].a]);

                if (edgesToSplit.Contains(perimeter[i]))
                {
                    Vertex mix = Vertex.Mix(vertices[perimeter[i].a], vertices[perimeter[i].b], .5f);

                    // split current poly line
                    n_indexes[index].Add(n_vertices[index].Count);
                    n_vertices[index].Add(mix);

                    // add the centroid vertex
                    n_indexes[index].Add(n_vertices[index].Count);
                    n_vertices[index].Add(centroid);

                    // advance the poly line index
                    index = (index + 1) % splitCount;

                    // then add the edge center vertex and move on
                    n_vertices[index].Add(mix);
                }
            }

            List <ConnectFaceRebuildData> faces = new List <ConnectFaceRebuildData>();

            for (int i = 0; i < n_vertices.Count; i++)
            {
                FaceRebuildData f = AppendElements.FaceWithVertices(n_vertices[i], false);
                if (f == null)
                {
                    faces.Clear();
                    return(null);
                }
                faces.Add(new ConnectFaceRebuildData(f, n_indexes[i]));
            }

            return(faces);
        }
        public static void TestComparison_IVEC3()
        {
            IntVec3 a = (IntVec3)RandVec3();
            IntVec3 b = (IntVec3)(a.vec * 2.3f);
            IntVec3 c = (IntVec3) new Vector3(a.x, a.y + .001f, a.z);
            IntVec3 d = (IntVec3) new Vector3(a.x, a.y, a.z);

            IntVec3[] arr = ArrayUtility.Fill <IntVec3>(24, (i) => { return(i % 2 == 0 ? a : (IntVec3)RandVec3()); });

            Assert.IsFalse(a == b);
            Assert.IsFalse(a == c);
            Assert.IsTrue(a == d);
            Assert.IsFalse(a.GetHashCode() == b.GetHashCode());
            Assert.IsFalse(a.GetHashCode() == c.GetHashCode());
            Assert.IsTrue(a.GetHashCode() == d.GetHashCode());
            Assert.AreEqual(13, arr.Distinct().Count());
        }
        public static void TestComparison_EDGE()
        {
            Edge a = (Edge)RandEdge();
            Edge b = (Edge)(a + 20);
            Edge c = (Edge) new Edge(a.a + 10, a.a);
            Edge d = (Edge) new Edge(a.a, a.b);

            Edge[] arr = ArrayUtility.Fill <Edge>(24, (i) => { return(i % 2 == 0 ? a : (Edge)RandEdge()); });

            Assert.IsFalse(a == b, "a == b");
            Assert.IsFalse(a == c, "a == c");
            Assert.IsFalse(a.GetHashCode() == b.GetHashCode(), "a.GetHashCode() == b.GetHashCode()");
            Assert.IsFalse(a.GetHashCode() == c.GetHashCode(), "a.GetHashCode() == c.GetHashCode()");
            Assert.IsTrue(a.GetHashCode() == d.GetHashCode(), "a.GetHashCode() == d.GetHashCode()");
            Assert.AreEqual(a, d, "Assert.AreEqual(a, d);");
            Assert.IsTrue(a == d, "Assert.IsTrue(a != d);");
            Assert.AreEqual(13, arr.Distinct().Count(), "Assert.AreEqual(13, arr.Distinct().Count());");
        }
Exemple #4
0
        /// <summary>
        /// Reverses the orientation of the middle edge in a quad.
        /// <![CDATA[
        /// ```
        /// .  _____        _____
        /// . |\    |      |    /|
        /// . |  \  |  =>  |  /  |
        /// . |____\|      |/____|
        /// ```
        /// ]]>
        /// </summary>
        /// <param name="mesh">The mesh that face belongs to.</param>
        /// <param name="face">The target face.</param>
        /// <returns>True if successful, false if not. Operation will fail if face does not contain two triangles with exactly 2 shared vertices.</returns>
        public static bool FlipEdge(this ProBuilderMesh mesh, Face face)
        {
            if (mesh == null)
            {
                throw new ArgumentNullException("mesh");
            }

            if (face == null)
            {
                throw new ArgumentNullException("face");
            }

            int[] indexes = face.indexesInternal;

            if (indexes.Length != 6)
            {
                return(false);
            }

            int[] mode = ArrayUtility.Fill <int>(1, indexes.Length);

            for (int x = 0; x < indexes.Length - 1; x++)
            {
                for (int y = x + 1; y < indexes.Length; y++)
                {
                    if (indexes[x] == indexes[y])
                    {
                        mode[x]++;
                        mode[y]++;
                    }
                }
            }

            if (mode[0] + mode[1] + mode[2] != 5 ||
                mode[3] + mode[4] + mode[5] != 5)
            {
                return(false);
            }

            int i0 = indexes[mode[0] == 1 ? 0 : mode[1] == 1 ? 1 : 2];
            int i1 = indexes[mode[3] == 1 ? 3 : mode[4] == 1 ? 4 : 5];

            int used = -1;

            if (mode[0] == 2)
            {
                used       = indexes[0];
                indexes[0] = i1;
            }
            else if (mode[1] == 2)
            {
                used       = indexes[1];
                indexes[1] = i1;
            }
            else if (mode[2] == 2)
            {
                used       = indexes[2];
                indexes[2] = i1;
            }

            if (mode[3] == 2 && indexes[3] != used)
            {
                indexes[3] = i0;
            }
            else if (mode[4] == 2 && indexes[4] != used)
            {
                indexes[4] = i0;
            }
            else if (mode[5] == 2 && indexes[5] != used)
            {
                indexes[5] = i0;
            }

            face.InvalidateCache();

            return(true);
        }
        /// <summary>
        /// Append a new face to the ProBuilderMesh.
        /// </summary>
        /// <param name="mesh">The mesh target.</param>
        /// <param name="positions">The new vertex positions to add.</param>
        /// <param name="colors">The new colors to add (must match positions length).</param>
        /// <param name="uvs">The new uvs to add (must match positions length).</param>
        /// <param name="face">A face with the new triangle indexes. The indexes should be 0 indexed.</param>
        /// <param name="common"></param>
        /// <returns>The new face as referenced on the mesh.</returns>
        internal static Face AppendFace(
            this ProBuilderMesh mesh,
            Vector3[] positions,
            Color[] colors,
            Vector2[] uv0s,
            Vector4[] uv2s,
            Vector4[] uv3s,
            Face face,
            int[] common)
        {
            if (mesh == null)
            {
                throw new ArgumentNullException("mesh");
            }

            if (positions == null)
            {
                throw new ArgumentNullException("positions");
            }

            if (face == null)
            {
                throw new ArgumentNullException("face");
            }

            int faceVertexCount = positions.Length;

            if (common == null)
            {
                common = new int[faceVertexCount];
                for (int i = 0; i < faceVertexCount; i++)
                {
                    common[i] = -1;
                }
            }

            int vertexCount = mesh.vertexCount;

            var mc  = mesh.HasArrays(MeshArrays.Color);
            var fc  = colors != null;
            var mt0 = mesh.HasArrays(MeshArrays.Texture0);
            var ft0 = uv0s != null;
            var mt2 = mesh.HasArrays(MeshArrays.Texture2);
            var ft2 = uv2s != null;
            var mt3 = mesh.HasArrays(MeshArrays.Texture3);
            var ft3 = uv3s != null;

            Vector3[]      newPositions = new Vector3[vertexCount + faceVertexCount];
            Color[]        newColors    = (mc || fc) ? new Color[vertexCount + faceVertexCount] : null;
            Vector2[]      newTexture0s = (mt0 || ft0) ? new Vector2[vertexCount + faceVertexCount] : null;
            List <Vector4> newTexture2s = (mt2 || ft2) ? new List <Vector4>() : null;
            List <Vector4> newTexture3s = (mt3 || ft3) ? new List <Vector4>() : null;

            List <Face> faces = new List <Face>(mesh.facesInternal);

            Array.Copy(mesh.positionsInternal, 0, newPositions, 0, vertexCount);
            Array.Copy(positions, 0, newPositions, vertexCount, faceVertexCount);

            if (mc || fc)
            {
                Array.Copy(mc ? mesh.colorsInternal : ArrayUtility.Fill(Color.white, vertexCount), 0, newColors, 0,
                           vertexCount);
                Array.Copy(fc ? colors : ArrayUtility.Fill(Color.white, faceVertexCount), 0, newColors, vertexCount,
                           colors.Length);
            }

            if (mt0 || ft0)
            {
                Array.Copy(mt0 ? mesh.texturesInternal : ArrayUtility.Fill(Vector2.zero, vertexCount), 0, newTexture0s, 0,
                           vertexCount);
                Array.Copy(ft0 ? uv0s : ArrayUtility.Fill(Vector2.zero, faceVertexCount), 0, newTexture0s,
                           mesh.texturesInternal.Length, faceVertexCount);
            }

            if (mt2 || ft2)
            {
                newTexture2s.AddRange(mt2 ? mesh.textures2Internal : new Vector4[vertexCount].ToList());
                newTexture2s.AddRange(ft2 ? uv2s : new Vector4[faceVertexCount]);
            }

            if (mt3 || ft3)
            {
                newTexture3s.AddRange(mt3 ? mesh.textures3Internal : new Vector4[vertexCount].ToList());
                newTexture3s.AddRange(ft3 ? uv3s : new Vector4[faceVertexCount]);
            }

            face.ShiftIndexesToZero();
            face.ShiftIndexes(vertexCount);

            faces.Add(face);

            for (int i = 0; i < common.Length; i++)
            {
                if (common[i] < 0)
                {
                    mesh.AddSharedVertex(new SharedVertex(new int[] { i + vertexCount }));
                }
                else
                {
                    mesh.AddToSharedVertex(common[i], i + vertexCount);
                }
            }

            mesh.positions         = newPositions;
            mesh.colors            = newColors;
            mesh.textures          = newTexture0s;
            mesh.faces             = faces;
            mesh.textures2Internal = newTexture2s;
            mesh.textures3Internal = newTexture3s;

            return(face);
        }
Exemple #6
0
        static List <ConnectFaceRebuildData> ConnectIndexesPerFace(
            Face face,
            List <int> indexes,
            List <Vertex> vertices,
            Dictionary <int, int> lookup,
            int sharedIndexOffset)
        {
            if (indexes.Count < 3)
            {
                return(null);
            }

            List <Edge> perimeter = WingedEdge.SortEdgesByAdjacency(face);

            int splitCount = indexes.Count;

            List <List <Vertex> > n_vertices      = ArrayUtility.Fill <List <Vertex> >(x => { return(new List <Vertex>()); }, splitCount);
            List <List <int> >    n_sharedIndexes = ArrayUtility.Fill <List <int> >(x => { return(new List <int>()); }, splitCount);
            List <List <int> >    n_indexes       = ArrayUtility.Fill <List <int> >(x => { return(new List <int>()); }, splitCount);

            Vertex  center = Vertex.Average(vertices, indexes);
            Vector3 nrm    = Math.Normal(vertices, face.indexesInternal);

            int index = 0;

            for (int i = 0; i < perimeter.Count; i++)
            {
                int cur = perimeter[i].a;

                n_vertices[index].Add(vertices[cur]);
                n_sharedIndexes[index].Add(lookup[cur]);

                if (indexes.Contains(cur))
                {
                    n_indexes[index].Add(n_vertices[index].Count);
                    n_vertices[index].Add(center);
                    n_sharedIndexes[index].Add(sharedIndexOffset);

                    index = (index + 1) % splitCount;

                    n_indexes[index].Add(n_vertices[index].Count);
                    n_vertices[index].Add(vertices[cur]);
                    n_sharedIndexes[index].Add(lookup[cur]);
                }
            }

            List <ConnectFaceRebuildData> faces = new List <ConnectFaceRebuildData>();

            for (int i = 0; i < n_vertices.Count; i++)
            {
                if (n_vertices[i].Count < 3)
                {
                    continue;
                }

                FaceRebuildData f = AppendElements.FaceWithVertices(n_vertices[i], false);
                f.sharedIndexes = n_sharedIndexes[i];

                Vector3 fn = Math.Normal(n_vertices[i], f.face.indexesInternal);

                if (Vector3.Dot(nrm, fn) < 0)
                {
                    f.face.Reverse();
                }

                faces.Add(new ConnectFaceRebuildData(f, n_indexes[i]));
            }

            return(faces);
        }
 public static void TestHashCollisions_IVEC3()
 {
     IntVec3[] ivec3 = ArrayUtility.Fill <IntVec3>(TestIterationCount, (i) => { return((IntVec3)RandVec3()); });
     Assert.IsTrue(TestHashUtility.GetCollisionsCount(ivec3) < TestIterationCount * .05f);
 }
 public static void TestHashCollisions_EDGE()
 {
     Edge[] edge = ArrayUtility.Fill <Edge>(TestIterationCount, (i) => { return(RandEdge()); });
     Assert.IsTrue(TestHashUtility.GetCollisionsCount(edge) < TestIterationCount * .05f);
 }