예제 #1
0
        public void CannotSplitFaceBadArguments()
        {
            PlanktonMesh pMesh = new PlanktonMesh();

            // Create one vertex for each corner of a square
            pMesh.Vertices.Add(0, 0, 0); // 0
            pMesh.Vertices.Add(1, 0, 0); // 1
            pMesh.Vertices.Add(1, 1, 0); // 2
            pMesh.Vertices.Add(0, 1, 0); // 3

            // Create one quadrangular face
            pMesh.Faces.AddFace(0, 1, 2, 3);

            // First halfedge is a boundary
            Assert.AreEqual(-1, pMesh.Faces.SplitFace(1, 4));

            // Second halfedge is a boundary
            Assert.AreEqual(-1, pMesh.Faces.SplitFace(4, 1));

            // Same halfedge used for both arguments
            Assert.AreEqual(-1, pMesh.Faces.SplitFace(0, 0));

            // Second halfedge is successor to first
            Assert.AreEqual(-1, pMesh.Faces.SplitFace(0, 2));

            // Second halfedge is predecessor to first
            Assert.AreEqual(-1, pMesh.Faces.SplitFace(0, 6));
        }
예제 #2
0
        /// <summary>
        /// This is the method that actually does the work.
        /// </summary>
        /// <param name="DA">The DA object can be used to retrieve data from input parameters and
        /// to store data in output parameters.</param>
        protected override void SolveInstance(IGH_DataAccess DA)
        {
            PlanktonMesh mesh = null;

            DA.GetData(0, ref mesh);
            DA.SetData(0, mesh.Dual());
        }
예제 #3
0
        public void CanSplitFace()
        {
            PlanktonMesh pMesh = new PlanktonMesh();
            
            // Create one vertex for each corner of a square
            pMesh.Vertices.Add(0, 0, 0); // 0
            pMesh.Vertices.Add(1, 0, 0); // 1
            pMesh.Vertices.Add(1, 1, 0); // 2
            pMesh.Vertices.Add(0, 1, 0); // 3
            
            // Create one quadrangular face
            pMesh.Faces.AddFace(0, 1, 2, 3);
            
            // Split face into two triangles
            int new_he = pMesh.Faces.SplitFace(0, 4);

            // Returned halfedge should be adjacent to old face (#0)
            Assert.AreEqual(0, pMesh.Halfedges[new_he].AdjacentFace);

            // Traverse from returned halfedge to new face
            int new_he_pair = pMesh.Halfedges.GetPairHalfedge(new_he);
            int new_face = pMesh.Halfedges[new_he_pair].AdjacentFace;
            
            Assert.AreEqual(1, new_face);
            
            // Check that both faces are now triangular
            Assert.AreEqual(3, pMesh.Faces.GetFaceVertices(0).Length);
            Assert.AreEqual(3, pMesh.Faces.GetFaceVertices(1).Length);
            
            // Check the halfedges of each face
            Assert.AreEqual(new int[] { 8, 0, 2 }, pMesh.Faces.GetHalfedges(0));
            Assert.AreEqual(new int[] { 9, 4, 6 }, pMesh.Faces.GetHalfedges(1));
        }
예제 #4
0
        public void CanSplitMergeInvariant()
        {
            // TODO: draw figure here...

            PlanktonMesh pMesh = new PlanktonMesh();

            // Create 3x3 grid of vertices
            pMesh.Vertices.Add(0, 2, 0); // 0
            pMesh.Vertices.Add(0, 1, 0); // 1
            pMesh.Vertices.Add(0, 0, 0); // 2
            pMesh.Vertices.Add(1, 2, 0); // 3
            pMesh.Vertices.Add(1, 1, 0); // 4 (center)
            pMesh.Vertices.Add(1, 0, 0); // 5
            pMesh.Vertices.Add(2, 2, 0); // 6
            pMesh.Vertices.Add(2, 1, 0); // 7
            pMesh.Vertices.Add(2, 0, 0); // 8

            pMesh.Faces.AddFace(2, 4, 1);
            pMesh.Faces.AddFace(7, 4, 8);
            pMesh.Faces.AddFace(0, 1, 4, 3);
            pMesh.Faces.AddFace(3, 4, 7, 6);

            int start_he = 8;
            Assert.AreEqual(start_he, pMesh.Halfedges.FindHalfedge(4, 8));
            Assert.AreEqual(2, pMesh.Halfedges.FindHalfedge(4, 1));

            // Split face into two triangles
            int new_he = pMesh.Vertices.SplitVertex(start_he, 2);

            // Merge them back again
            int old_he = pMesh.Vertices.MergeVertices(new_he);

            // We should be back where we started...
            Assert.AreEqual(start_he, old_he);
        }
예제 #5
0
    public static Mesh PlanktonToUnity(this PlanktonMesh plankton)
    {
        int vCount   = plankton.Vertices.Count;
        var vertices = new Vector3[vCount];

        for (int i = 0; i < vCount; i++)
        {
            PlanktonVertex v = plankton.Vertices[i];
            vertices[i] = new Vector3(v.X, v.Y, v.Z);
        }

        int fCount    = plankton.Faces.Count;
        var triangles = new int[fCount * 3];

        int[] faceVertices = new int[3];
        for (int i = 0; i < fCount; i++)
        {
            if (!plankton.Faces[i].IsUnused)
            {
                plankton.Faces.GetFaceVerticesNonAlloc(i, faceVertices);
                triangles[i * 3]     = faceVertices[0];
                triangles[i * 3 + 1] = faceVertices[1];
                triangles[i * 3 + 2] = faceVertices[2];
            }
        }

        var mesh = new Mesh();

        mesh.vertices  = vertices;
        mesh.uv        = plankton.Vertices.Select(v => v.data.UV).ToArray();
        mesh.normals   = plankton.Vertices.Select(v => v.data.Normal).ToArray();
        mesh.triangles = triangles;
        mesh.RecalculateTangents();
        return(mesh);
    }
예제 #6
0
        public void CanDualCube()
        {
            // Create a simple cube

            PlanktonMesh pMesh = new PlanktonMesh();

            pMesh.Vertices.Add(-0.5, -0.5, 0.5);
            pMesh.Vertices.Add(-0.5, -0.5, -0.5);
            pMesh.Vertices.Add(-0.5, 0.5, -0.5);
            pMesh.Vertices.Add(-0.5, 0.5, 0.5);
            pMesh.Vertices.Add(0.5, -0.5, 0.5);
            pMesh.Vertices.Add(0.5, -0.5, -0.5);
            pMesh.Vertices.Add(0.5, 0.5, -0.5);
            pMesh.Vertices.Add(0.5, 0.5, 0.5);

            pMesh.Faces.AddFace(3, 2, 1, 0);
            pMesh.Faces.AddFace(1, 5, 4, 0);
            pMesh.Faces.AddFace(2, 6, 5, 1);
            pMesh.Faces.AddFace(7, 6, 2, 3);
            pMesh.Faces.AddFace(4, 7, 3, 0);
            pMesh.Faces.AddFace(5, 6, 7, 4);

            var dual = pMesh.Dual();

            Assert.AreEqual(new int[] { 2, 3, 0, 1 }, dual.Vertices.GetVertexFaces(0));
        }
예제 #7
0
        public static Point3d MidPt(PlanktonMesh P, int E)
        {
            Point3d Pos1 = P.Vertices[P.Halfedges[2 * E].StartVertex].ToPoint3d();
            Point3d Pos2 = P.Vertices[P.Halfedges[2 * E + 1].StartVertex].ToPoint3d();

            return((Pos1 + Pos2) * 0.5);
        }
예제 #8
0
 public void CanTraverseUnusedVertex()
 {
     // Getting halfedges for unused vertex should return empty
     PlanktonMesh pMesh = new PlanktonMesh();
     pMesh.Vertices.Add(0, 0, 0);
     Assert.IsEmpty(pMesh.Vertices.GetHalfedges(0));
 }
예제 #9
0
        //--------------------------------------------------Calculate vertex normals methods------------------------------------------//
        /*The vertex normals are calculated as the weighted average of the adjacent face normals */

        //FACE NORMAL
        /* calculate the face normal (not normalised) as average of cross products of edge pairs (n-gon) */
        public Vector3d calcFaceNormal(PlanktonMesh pMesh, int faceIndex)
        {
            Vector3d[] edgesCCW = new Vector3d[pMesh.Vertices.Count];

            int[] faceHalfedges = pMesh.Faces.GetHalfedges(faceIndex);
            for (int i = 0; i < faceHalfedges.Length; i++)
            {
                int     startVertex  = pMesh.Halfedges[faceHalfedges[i]].StartVertex;
                Point3d start        = new Point3d(pMesh.Vertices[startVertex].X, pMesh.Vertices[startVertex].Y, pMesh.Vertices[startVertex].Z);
                int     nextHalfedge = pMesh.Halfedges[faceHalfedges[i]].NextHalfedge;
                int     endVertex    = pMesh.Halfedges[nextHalfedge].StartVertex;
                Point3d end          = new Point3d(pMesh.Vertices[endVertex].X, pMesh.Vertices[endVertex].Y, pMesh.Vertices[endVertex].Z);

                edgesCCW[i] = new Vector3d(end - start);
            }

            //shift edgesCCW
            Vector3d[] shift_edgesCCW = new Vector3d[edgesCCW.Length];
            for (int j = 0; j < edgesCCW.Length; j++)
            {
                shift_edgesCCW[j] = edgesCCW[(j + 1) % edgesCCW.Length];
            }

            //normal vector
            Vector3d normal = new Vector3d(0, 0, 0);

            for (int k = 0; k < edgesCCW.Length; k++)
            {
                normal += Vector3d.CrossProduct(edgesCCW[k], shift_edgesCCW[k]);
            }
            normal = normal / edgesCCW.Length;

            return(normal);
        }
예제 #10
0
        public void CanGetNormal()
        {
            PlanktonMesh pMesh = new PlanktonMesh();

            // Create 3x3 grid of vertices
            pMesh.Vertices.Add(0, 2, 0); // 0
            pMesh.Vertices.Add(0, 1, 0); // 1
            pMesh.Vertices.Add(0, 0, 0); // 2
            pMesh.Vertices.Add(1, 2, 0); // 3
            pMesh.Vertices.Add(1, 1, 0); // 4 (center)
            pMesh.Vertices.Add(1, 0, 0); // 5
            pMesh.Vertices.Add(2, 2, 0); // 6
            pMesh.Vertices.Add(2, 1, 0); // 7
            pMesh.Vertices.Add(2, 0, 0); // 8

            // Create four quadrangular faces
            pMesh.Faces.AddFace(0, 1, 4, 3);
            pMesh.Faces.AddFace(3, 4, 7, 6);
            pMesh.Faces.AddFace(1, 2, 5, 4);
            pMesh.Faces.AddFace(4, 5, 8, 7);

            Assert.AreEqual(new PlanktonXYZ(0, 0, 1), pMesh.Vertices.GetNormal(0)); // corner
            Assert.AreEqual(new PlanktonXYZ(0, 0, 1), pMesh.Vertices.GetNormal(7)); // edge
            Assert.AreEqual(new PlanktonXYZ(0, 0, 1), pMesh.Vertices.GetNormal(4)); // centre
        }
예제 #11
0
        /// <summary>
        /// This is the method that actually does the work.
        /// </summary>
        /// <param name="DA">The DA object is used to retrieve from inputs and store in outputs.</param>
        protected override void SolveInstance(IGH_DataAccess DA)
        {
            //Global variables
            PlanktonMesh pMesh = new PlanktonMesh();

            DA.GetData(0, ref pMesh);

            Matrix mV = null;

            DA.GetData(1, ref mV);

            //---------------------------------------------------------------

            //Detect number of peaks/troughs of each mode
            List <String> peaksPerMode   = new List <String>();
            List <String> troughsPerMode = new List <String>();

            for (int j = 0; j < mV.ColumnCount; j++)
            {
                peaksPerMode.Add(calcNumberOfPeaks(pMesh, mV, j, true));
                troughsPerMode.Add(calcNumberOfPeaks(pMesh, mV, j, false));
            }

            //---------------------------------------------------------------


            //Output
            DA.SetDataList(0, peaksPerMode);
            DA.SetDataList(1, troughsPerMode);
        }
예제 #12
0
        //HALFEDGE INDEX FROM VERTEX INDICES
        /* return halfedge index from given i and j vertex indices. -1 if halfedge doesn't exist */
        public int findHalfedgeIndex(PlanktonMesh pMesh, int i, int j)
        {
            //find halfedge from vertex i to j if it exists
            int halfedge_ij = pMesh.Halfedges.FindHalfedge(i, j);

            return halfedge_ij;
        }
예제 #13
0
        //COTANGENT LAPLACIAN
        /* calculate the cotangent Laplacian of the input mesh */
        public Matrix calcCotLaplacian(PlanktonMesh pMesh, List<double> cotEdgeWeights)
        {
            int n = pMesh.Vertices.Count;
            Matrix mL = new Matrix(n, n);

            for (int i = 0; i < n; i++)
            {
                for (int j = 0; j < n; j++)
                {
                    if (i == j)
                    {
                        mL[i, j] = calcCotVertexWeight(pMesh, i, cotEdgeWeights);
                    }
                    else
                    {
                        int edgeIndex = findHalfedgeIndex(pMesh, i, j);
                        if (edgeIndex != -1)
                        {
                            mL[i, j] = -1 * cotEdgeWeights[edgeIndex];
                        }
                    }
                }
            }
            return mL;
        }
예제 #14
0
        public void CanTruncateMesh()
        {
            // Create a simple cube

            PlanktonMesh pMesh = new PlanktonMesh();

            pMesh.Vertices.Add(-0.5, -0.5, 0.5);
            pMesh.Vertices.Add(-0.5, -0.5, -0.5);
            pMesh.Vertices.Add(-0.5, 0.5, -0.5);
            pMesh.Vertices.Add(-0.5, 0.5, 0.5);
            pMesh.Vertices.Add(0.5, -0.5, 0.5);
            pMesh.Vertices.Add(0.5, -0.5, -0.5);
            pMesh.Vertices.Add(0.5, 0.5, -0.5);
            pMesh.Vertices.Add(0.5, 0.5, 0.5);

            pMesh.Faces.AddFace(3, 2, 1, 0);
            pMesh.Faces.AddFace(1, 5, 4, 0);
            pMesh.Faces.AddFace(2, 6, 5, 1);
            pMesh.Faces.AddFace(7, 6, 2, 3);
            pMesh.Faces.AddFace(4, 7, 3, 0);
            pMesh.Faces.AddFace(5, 6, 7, 4);

            Assert.AreEqual(6, pMesh.Faces.Count);

            var tMesh = pMesh.TruncateVertices();

            Assert.AreEqual(pMesh.Faces.Count + pMesh.Vertices.Count, tMesh.Faces.Count);

            // TODO: geometrical check
        }
예제 #15
0
        /// <summary>
        /// This is the method that actually does the work.
        /// </summary>
        /// <param name="DA">The DA object is used to retrieve from inputs and store in outputs.</param>
        protected override void SolveInstance(IGH_DataAccess DA)
        {
            //------------------INPUT--------------------//
            PlanktonMesh pMesh = new PlanktonMesh();

            DA.GetData(0, ref pMesh);

            Plane pln = new Plane();

            DA.GetData(1, ref pln);



            //------------------CALCULATE--------------------//
            PMeshExt pMeshE = new PMeshExt(pMesh);

            if (!pMeshE.isMeshTriangulated())
            {
                this.AddRuntimeMessage(GH_RuntimeMessageLevel.Error, "The mesh has to be triangulated");
            }

            Point3d[] verticesXYZ = pMeshE.convertVerticesToXYZ();

            Vector3d[] vertexAreas = pMeshE.calcVertexVoronoiAreas(pln);



            //------------------OUTPUT--------------------//
            DA.SetDataList(0, verticesXYZ);
            DA.SetDataList(1, vertexAreas);
        }
예제 #16
0
        public void CanCompact()
        {
            PlanktonMesh pMesh = new PlanktonMesh();

            // Create vertices in 3x2 grid
            pMesh.Vertices.Add(0, 0, 0); // 0
            pMesh.Vertices.Add(1, 0, 0); // 1
            pMesh.Vertices.Add(1, 1, 0); // 2
            pMesh.Vertices.Add(0, 1, 0); // 3
            pMesh.Vertices.Add(2, 0, 0); // 4
            pMesh.Vertices.Add(2, 1, 0); // 5

            // Create two quadrangular faces
            pMesh.Faces.AddFace(0, 1, 2, 3);
            pMesh.Faces.AddFace(1, 4, 5, 2);

            // Remove the first face and compact
            pMesh.Faces.RemoveFace(0);
            pMesh.Vertices.CullUnused();
            pMesh.Compact();

            // Check some things about the compacted mesh
            Assert.AreEqual(4, pMesh.Vertices.Count);
            Assert.AreEqual(1, pMesh.Faces.Count);
            Assert.AreEqual(8, pMesh.Halfedges.Count);
            Assert.AreEqual(new int[] { 0, 2, 3, 1 }, pMesh.Faces.GetFaceVertices(0));
        }
예제 #17
0
        public void CanCalculateVolume()
        {
            // Create a simple cube

            PlanktonMesh pMesh = new PlanktonMesh();

            pMesh.Vertices.Add(-0.5, -0.5, 0.5);
            pMesh.Vertices.Add(-0.5, -0.5, -0.5);
            pMesh.Vertices.Add(-0.5, 0.5, -0.5);
            pMesh.Vertices.Add(-0.5, 0.5, 0.5);
            pMesh.Vertices.Add(0.5, -0.5, 0.5);
            pMesh.Vertices.Add(0.5, -0.5, -0.5);
            pMesh.Vertices.Add(0.5, 0.5, -0.5);
            pMesh.Vertices.Add(0.5, 0.5, 0.5);

            pMesh.Faces.AddFace(3, 2, 1, 0);
            pMesh.Faces.AddFace(1, 5, 4, 0);
            pMesh.Faces.AddFace(2, 6, 5, 1);
            pMesh.Faces.AddFace(7, 6, 2, 3);
            pMesh.Faces.AddFace(4, 7, 3, 0);
            pMesh.Faces.AddFace(5, 6, 7, 4);

            // Calculate volume

            Assert.AreEqual(1, pMesh.Volume(), 1E-9);
        }
예제 #18
0
        public void CannotCollapseNonManifoldEdge()
        {
            PlanktonMesh pMesh = new PlanktonMesh();

            // Create vertices in 3x2 grid
            pMesh.Vertices.Add(-1, 0, 0);  // 0
            pMesh.Vertices.Add(0, -1, 0);  // 1
            pMesh.Vertices.Add(1, 0, 0);   // 2
            pMesh.Vertices.Add(0, 1, 0);   // 3
            pMesh.Vertices.Add(-1, -2, 0); // 4
            pMesh.Vertices.Add(0, -3, 0);  // 5
            pMesh.Vertices.Add(1, -2, 0);  // 6

            // Create several triangular faces
            pMesh.Faces.AddFace(0, 1, 3);
            pMesh.Faces.AddFace(1, 2, 3);
            pMesh.Faces.AddFace(0, 4, 1);
            pMesh.Faces.AddFace(4, 5, 1);
            // And one quad face
            pMesh.Faces.AddFace(1, 5, 6, 2);

            pMesh.Faces.Stellate(0);
            pMesh.Faces.Stellate(1);

            Assert.AreEqual(9, pMesh.Faces.Count);

            Assert.AreEqual(-1, pMesh.Halfedges.CollapseEdge(2));
            Assert.AreEqual(-1, pMesh.Halfedges.CollapseEdge(6));
        }
예제 #19
0
        public void CanCollapseSameFace(int h)
        {
            //   3-------2
            //   |  f1   |      Tries to collapse the halfedge...
            //   |       |      * 0 - from vertex 1 to vertex 4
            //   |   4   |      * 1 - from vertex 4 to vertex 1
            //   | /   \ |      * 2 - from vertex 4 to vertex 0
            //   |/ f0  \|      * 3 - from vertex 0 to vertex 4
            //   0-------1

            PlanktonMesh mesh = new PlanktonMesh();

            mesh.Vertices.Add(0, 0, 0);     // 0
            mesh.Vertices.Add(100, 0, 0);   // 1
            mesh.Vertices.Add(100, 100, 0); // 2
            mesh.Vertices.Add(0, 100, 0);   // 3
            mesh.Vertices.Add(50, 50, 0);   // 4

            mesh.Faces.AddFace(1, 4, 0);
            mesh.Faces.AddFace(new int[] { 1, 2, 3, 0, 4 });

            mesh.Halfedges.CollapseEdge(h);

            Assert.IsTrue(mesh.Faces[0].IsUnused, "face 0 should be unset");
            Assert.AreEqual(4, mesh.Faces.GetFaceVertices(1).Length, "face 1 should have 4 vertices");
        }
예제 #20
0
        public void CanCollapseValenceThreeVertex()
        {
            PlanktonMesh pMesh = new PlanktonMesh();

            // Create mesh with one triangular face
            pMesh.Vertices.Add(0, 0, 0);   // 0
            pMesh.Vertices.Add(2, 0, 0);   // 1
            pMesh.Vertices.Add(1, 1.4, 0); // 2
            pMesh.Faces.AddFace(0, 1, 2);

            // create vertex at center and get a halfedge pointing *towards* it
            int v = pMesh.Faces.Stellate(0);
            int h = pMesh.Vertices.GetIncomingHalfedge(v);

            // count faces before collapse
            Assert.AreEqual(3, pMesh.Faces.Count);

            // attempt to collapse one of the internal edges
            Assert.GreaterOrEqual(0, pMesh.Halfedges.CollapseEdge(h));

            // there should be 6 unused halfedges now...
            Assert.AreEqual(6, pMesh.Halfedges.Where(q => q.IsUnused).Count());

            // compact and count faces again
            pMesh.Compact();
            Assert.AreEqual(1, pMesh.Faces.Count);
        }
예제 #21
0
        //RMS
        public double calcRMS(PlanktonMesh pMesh, Matrix mV, List <int> eigsIndices, List <double> weights, double scale, List <Vector3d> displDir, List <double> distanceSignal)
        {
            List <double>   nodalValues         = nodalLinearCombination(weights, mV, eigsIndices);
            List <Vector3d> vertexDisplacements = mapToDisplacements(nodalValues, displDir, scale);

            List <double> vertexDeviations = new List <double>();

            for (int i = 0; i < pMesh.Vertices.Count; i++)
            {
                Point3d vPos    = new Point3d(pMesh.Vertices[i].X, pMesh.Vertices[i].Y, pMesh.Vertices[i].Z);
                Point3d vPosNew = vPos + vertexDisplacements[i];

                Point3d vPosSrf = vPos + displDir[i] * distanceSignal[i];

                double deviation = vPosNew.DistanceTo(vPosSrf);
                vertexDeviations.Add(deviation);
            }

            double rms = 0.0;

            foreach (double dev in vertexDeviations)
            {
                rms += Math.Pow(dev, 2);
            }
            double n = (double)vertexDeviations.Count;

            rms /= n;
            rms  = Math.Sqrt(rms);
            return(rms);
        }
예제 #22
0
        public void CanCalculateVolume()
        {
            // Create a simple cube

            PlanktonMesh pMesh = new PlanktonMesh();

            pMesh.Vertices.Add(-0.5, -0.5, 0.5);
            pMesh.Vertices.Add(-0.5, -0.5, -0.5);
            pMesh.Vertices.Add(-0.5, 0.5, -0.5);
            pMesh.Vertices.Add(-0.5, 0.5, 0.5);
            pMesh.Vertices.Add(0.5, -0.5, 0.5);
            pMesh.Vertices.Add(0.5, -0.5, -0.5);
            pMesh.Vertices.Add(0.5, 0.5, -0.5);
            pMesh.Vertices.Add(0.5, 0.5, 0.5);

            pMesh.Faces.AddFace(3, 2, 1, 0);
            pMesh.Faces.AddFace(1, 5, 4, 0);
            pMesh.Faces.AddFace(2, 6, 5, 1);
            pMesh.Faces.AddFace(7, 6, 2, 3);
            pMesh.Faces.AddFace(4, 7, 3, 0);
            pMesh.Faces.AddFace(5, 6, 7, 4);

            // Calculate volume

            Assert.AreEqual(1, pMesh.Volume(), 1E-9);
        }
예제 #23
0
        //Find the two indexes in the warpIndexList which correspond to the two neighbour vertices in the warp direction
        int[] findWarpIndexes(PlanktonMesh pMesh, int vIndex, List <int> warpIndexList)
        {
            int[] wIndexes = new int[2];

            //find center vertex in warp index list (every vertex has a warp direction)
            int cIndexW = warpIndexList.IndexOf(vIndex);

            //extract index+1 and index-1 (always works because only internal vertices are considered)
            int v0IndexW = warpIndexList[cIndexW - 1];
            int v1IndexW = warpIndexList[cIndexW + 1];

            //find index of these two in vNeighbours
            int[] vNeighbours = pMesh.Vertices.GetVertexNeighbours(vIndex);
            int   v0IndexN    = Array.IndexOf(vNeighbours, v0IndexW);
            int   v1IndexN    = Array.IndexOf(vNeighbours, v1IndexW);

            if (v0IndexN != -1 && v1IndexN != -1)
            {
                wIndexes[0] = v0IndexN;
                wIndexes[1] = v1IndexN;
            }
            else
            {
                this.AddRuntimeMessage(GH_RuntimeMessageLevel.Error, "Not able to find warp direction within the neighbourhood of vertex " + vIndex);
            }

            return(wIndexes);
        }
예제 #24
0
        public void CanSplitFace()
        {
            PlanktonMesh pMesh = new PlanktonMesh();

            // Create one vertex for each corner of a square
            pMesh.Vertices.Add(0, 0, 0); // 0
            pMesh.Vertices.Add(1, 0, 0); // 1
            pMesh.Vertices.Add(1, 1, 0); // 2
            pMesh.Vertices.Add(0, 1, 0); // 3

            // Create one quadrangular face
            pMesh.Faces.AddFace(0, 1, 2, 3);

            // Split face into two triangles
            int new_he = pMesh.Faces.SplitFace(0, 4);

            // Returned halfedge should be adjacent to old face (#0)
            Assert.AreEqual(0, pMesh.Halfedges[new_he].AdjacentFace);

            // Traverse from returned halfedge to new face
            int new_he_pair = pMesh.Halfedges.GetPairHalfedge(new_he);
            int new_face    = pMesh.Halfedges[new_he_pair].AdjacentFace;

            Assert.AreEqual(1, new_face);

            // Check that both faces are now triangular
            Assert.AreEqual(3, pMesh.Faces.GetFaceVertices(0).Length);
            Assert.AreEqual(3, pMesh.Faces.GetFaceVertices(1).Length);

            // Check the halfedges of each face
            Assert.AreEqual(new int[] { 8, 0, 2 }, pMesh.Faces.GetHalfedges(0));
            Assert.AreEqual(new int[] { 9, 4, 6 }, pMesh.Faces.GetHalfedges(1));
        }
예제 #25
0
        //Convert polyline points to mesh indexes
        List <int> convertPolyToMeshIndexes(PlanktonMesh pMesh, Polyline pl)
        {
            List <int> plIndexes = new List <int>();

            List <Point3d> verticesXYZ = extractMeshVerticesXYZ(pMesh);
            List <Point3d> polylinePts = new List <Point3d>();

            for (int i = 0; i < pl.Count; i++)
            {
                polylinePts.Add(pl[i]);
            }

            foreach (Point3d pt in polylinePts)
            {
                int index = verticesXYZ.IndexOf(pt);

                if (index == -1)
                {
                    this.AddRuntimeMessage(GH_RuntimeMessageLevel.Error, "Was not able to find point P(" + pt.X + "," + pt.Y + "," + pt.Z + ") amongst the vertices in the mesh");
                }
                else
                {
                    plIndexes.Add(index);
                }
            }

            return(plIndexes);
        }
예제 #26
0
        //Methods

        //Create bitmap frame as bounding box of vertices in mesh
        public Rectangle createFrame(PlanktonMesh pMesh)
        {
            //desired max frame dimension
            int dim = 300;

            List <double> xCoord = new List <double>();
            List <double> yCoord = new List <double>();

            foreach (PlanktonVertex pV in pMesh.Vertices)
            {
                xCoord.Add(pV.X);
                yCoord.Add(pV.Y);
            }

            double xRange = xCoord.Max() - xCoord.Min();
            double yRange = yCoord.Max() - yCoord.Min();


            //Compare and scale according to desired dimension
            double ratio = dim / xRange;

            if (yRange > xRange)
            {
                ratio = dim / yRange;
            }

            int w = (int)Math.Ceiling(xRange * ratio);
            int h = (int)Math.Ceiling(yRange * ratio);

            Rectangle rec = new Rectangle(0, 0, w, h);

            return(rec);
        }
예제 #27
0
        public void CannotSplitFaceBadArguments()
        {
            PlanktonMesh pMesh = new PlanktonMesh();

            // Create one vertex for each corner of a square
            pMesh.Vertices.Add(0, 0, 0); // 0
            pMesh.Vertices.Add(1, 0, 0); // 1
            pMesh.Vertices.Add(1, 1, 0); // 2
            pMesh.Vertices.Add(0, 1, 0); // 3

            // Create one quadrangular face
            pMesh.Faces.AddFace(0, 1, 2, 3);

            // First halfedge is a boundary
            Assert.AreEqual(-1, pMesh.Faces.SplitFace(1, 4));

            // Second halfedge is a boundary
            Assert.AreEqual(-1, pMesh.Faces.SplitFace(4, 1));

            // Same halfedge used for both arguments
            Assert.AreEqual(-1, pMesh.Faces.SplitFace(0, 0));

            // Second halfedge is successor to first
            Assert.AreEqual(-1, pMesh.Faces.SplitFace(0, 2));

            // Second halfedge is predecessor to first
            Assert.AreEqual(-1, pMesh.Faces.SplitFace(0, 6));
        }
예제 #28
0
        PlanktonMesh PMeshFromPolylines(List <Polyline> faces)
        {
            var pMesh = new PlanktonMesh();
            //add n-gon faces
            var verts = new List <Point3d>();

            for (int i = 0; i < faces.Count; i++)
            {
                var currFace = new List <int>();

                for (int j = 0; j < faces[i].Count - 1; j++)
                {
                    var currPt = faces[i].PointAt(j);
                    var id     = verts.IndexOf(currPt);
                    if (id < 0)
                    {
                        //push a vertex to list
                        //push that index to current face
                        pMesh.Vertices.Add(currPt.X, currPt.Y, currPt.Z);
                        verts.Add(currPt);
                        currFace.Add(pMesh.Vertices.Count - 1);
                    }
                    else
                    {
                        //push this index to current face
                        currFace.Add(id);
                    }
                }

                pMesh.Faces.AddFace(currFace);
            }

            return(pMesh);
        }
예제 #29
0
        public void CanGetNormals()
        {
            PlanktonMesh pMesh = new PlanktonMesh();

            // Create 3x3 grid of vertices
            pMesh.Vertices.Add(0, 2, 0); // 0
            pMesh.Vertices.Add(0, 1, 0); // 1
            pMesh.Vertices.Add(0, 0, 0); // 2
            pMesh.Vertices.Add(1, 2, 0); // 3
            pMesh.Vertices.Add(1, 1, 0); // 4 (center)
            pMesh.Vertices.Add(1, 0, 0); // 5
            pMesh.Vertices.Add(2, 2, 0); // 6
            pMesh.Vertices.Add(2, 1, 0); // 7
            pMesh.Vertices.Add(2, 0, 0); // 8

            // Create four quadrangular faces
            pMesh.Faces.AddFace(0, 1, 4, 3);
            pMesh.Faces.AddFace(3, 4, 7, 6);
            pMesh.Faces.AddFace(1, 2, 5, 4);
            pMesh.Faces.AddFace(4, 5, 8, 7);

            var expected = Enumerable.Repeat(new PlanktonXYZ(0, 0, 1), 9).ToArray();

            Assert.AreEqual(expected, pMesh.Vertices.GetNormals());
        }
예제 #30
0
        public static Vector3d Normal(PlanktonMesh P, int V)
        {
            Point3d  Vertex = P.Vertices[V].ToPoint3d();
            Vector3d Norm   = new Vector3d();

            int[]      OutEdges   = P.Vertices.GetHalfedges(V);
            int[]      Neighbours = P.Vertices.GetVertexNeighbours(V);
            Vector3d[] OutVectors = new Vector3d[Neighbours.Length];
            int        Valence    = P.Vertices.GetValence(V);

            for (int j = 0; j < Valence; j++)
            {
                OutVectors[j] = P.Vertices[Neighbours[j]].ToPoint3d() - Vertex;
            }

            for (int j = 0; j < Valence; j++)
            {
                if (P.Halfedges[OutEdges[(j + 1) % Valence]].AdjacentFace != -1)
                {
                    Norm += (Vector3d.CrossProduct(OutVectors[(j + 1) % Valence], OutVectors[j]));
                }
            }

            Norm.Unitize();
            return(Norm);
        }
예제 #31
0
        /// <summary>
        /// This is the method that actually does the work.
        /// </summary>
        /// <param name="DA">The DA object is used to retrieve from inputs and store in outputs.</param>
        protected override void SolveInstance(IGH_DataAccess DA)
        {
            //Global variables
            List <Point3d> list_pt_Vertices = new List <Point3d>();

            DA.GetDataList(0, list_pt_Vertices);

            List <Polyline> list_pl_FacePolygons = new List <Polyline>();

            //convert from curve to polyline since pManager only takes curves
            List <Curve> list_crv_FacePolygons = new List <Curve>();

            DA.GetDataList(1, list_crv_FacePolygons);
            foreach (Curve crv in list_crv_FacePolygons)
            {
                Polyline pl;
                crv.TryGetPolyline(out pl);
                list_pl_FacePolygons.Add(pl);
            }

            //Create plankton mesh
            PlanktonMesh pMesh = createPlanktonMesh(list_pt_Vertices, list_pl_FacePolygons);

            DA.SetData(0, pMesh);
        }
예제 #32
0
    /// <summary>
    /// Returns all the holes on the specified mesh, ignoring seams along the UV edge.
    /// </summary>
    public static IEnumerable <List <int> > AllBorderLoops(this PlanktonMesh mesh)
    {
        HashSet <int> seenEdges  = new HashSet <int>();
        List <int>    startEdges = new List <int>();

        foreach (var edge in AllBorderEdges(mesh.Halfedges))
        {
            if (!seenEdges.Contains(edge))
            {
                startEdges.Add(edge);
                foreach (var borderEdge in TraceBorderFromEdge(mesh, edge))
                {
                    seenEdges.Add(borderEdge);
                }
            }
        }

        foreach (var edge in startEdges)
        {
            foreach (var loop in CollapseSeamEdgeIntoLoops(mesh, TraceBorderFromEdge(mesh, edge).ToList()))
            {
                yield return(loop);
            }
        }
    }
예제 #33
0
    public static PlanktonMesh UnityToPlankton(this Mesh mesh)
    {
        var plankton = new PlanktonMesh();

        // Cache the mesh data.
        var vertices  = mesh.vertices;
        var triangles = mesh.triangles;
        var uvs       = mesh.uv;
        var normals   = mesh.normals;

        for (int i = 0; i < vertices.Length; i++)
        {
            plankton.Vertices.Add(
                vertices[i].x,
                vertices[i].y,
                vertices[i].z,
                new PlanktonVertexData()
            {
                UV = uvs[i], Normal = normals[i]
            }
                );
        }

        int[] triIndices = new int[3];
        for (int i = 0; i < triangles.Length; i += 3)
        {
            triIndices[0] = triangles[i];
            triIndices[1] = triangles[i + 1];
            triIndices[2] = triangles[i + 2];
            plankton.Faces.AddFace(triIndices);
        }

        return(plankton);
    }
예제 #34
0
    public static HashSet <int> FindConnectedFaces(this PlanktonMesh mesh, int startFaceIndex, HashSet <int> blockedEdges)
    {
        HashSet <int> seenFaces = new HashSet <int>();
        Queue <int>   queued    = new Queue <int>();

        seenFaces.Add(startFaceIndex);
        queued.Enqueue(startFaceIndex);

        int[] foundEdges = new int[3];
        while (queued.Count > 0)
        {
            int face = queued.Dequeue();

            int edgeNum = mesh.Faces.GetHalfedgesNonAlloc(face, foundEdges);
            for (int i = 0; i < edgeNum; i++)
            {
                var pairEdge = mesh.Halfedges.GetPairHalfedge(foundEdges[i]);
                int pairFace = mesh.Halfedges[pairEdge].AdjacentFace;
                if (pairFace != -1 && !seenFaces.Contains(pairFace) && !blockedEdges.Contains(pairEdge))
                {
                    queued.Enqueue(pairFace);
                    seenFaces.Add(pairFace);
                }
            }
        }

        return(seenFaces);
    }
예제 #35
0
        /// <summary>
        /// Creates a Rhino mesh from a Plankton halfedge mesh.
        /// Uses the face-vertex information available in the halfedge data structure.
        /// </summary>
        /// <returns>A <see cref="Mesh"/> which represents the source mesh (as best it can).</returns>
        /// <param name="source">A Plankton mesh to convert from.</param>
        /// <remarks>Any faces with five sides or more will be triangulated.</remarks>
        public static Mesh ToRhinoMesh(this PlanktonMesh source)
        {
            // could add different options for triangulating ngons later
            Mesh rMesh = new Mesh();

            foreach (PlanktonVertex v in source.Vertices)
            {
                rMesh.Vertices.Add(v.X, v.Y, v.Z);
            }
            for (int i = 0; i < source.Faces.Count; i++)
            {
                int[] fvs = source.Faces.GetFaceVertices(i);
                if (fvs.Length == 3)
                {
                    rMesh.Faces.AddFace(fvs[0], fvs[1], fvs[2]);
                }
                else if (fvs.Length == 4)
                {
                    rMesh.Faces.AddFace(fvs[0], fvs[1], fvs[2], fvs[3]);
                }
                else if (fvs.Length > 4)
                {
                    // triangulate about face center (fan)
                    var fc = source.Faces.GetFaceCenter(i);
                    rMesh.Vertices.Add(fc.X, fc.Y, fc.Z);
                    for (int j = 0; j < fvs.Length; j++)
                    {
                        rMesh.Faces.AddFace(fvs[j], fvs[(j + 1) % fvs.Length], rMesh.Vertices.Count - 1);
                    }
                }
            }
            return(rMesh);
        }
예제 #36
0
        public void CanCollapseBoundaryEdge()
        {
            PlanktonMesh pMesh = new PlanktonMesh();

            // Create one vertex for each corner of a square
            pMesh.Vertices.Add(0, 0, 0); // 0
            pMesh.Vertices.Add(1, 0, 0); // 1
            pMesh.Vertices.Add(1, 1, 0); // 2
            pMesh.Vertices.Add(0, 1, 0); // 3

            // Create one quadrangular face
            pMesh.Faces.AddFace(0, 1, 2, 3);

            int h_clps = 0;
            int h_clps_prev = pMesh.Halfedges[h_clps].PrevHalfedge;

            // Confirm face's first halfedge is the one to be collapsed
            Assert.AreEqual(h_clps, pMesh.Faces[0].FirstHalfedge);

            // Collapse edge
            int h_rtn = pMesh.Halfedges.CollapseEdge(h_clps);

            // Edge collapse should return successor around start vertex
            Assert.AreEqual(7, h_rtn);

            // Check face's first halfedge was updated
            Assert.AreNotEqual(h_clps, pMesh.Faces[0].FirstHalfedge);

            // Check for closed loop (without collapsed halfedge)
            Assert.AreEqual(new int[] { 2, 4, 6 }, pMesh.Faces.GetHalfedges(0));

            // Pair of predecessor to collapsed halfedge should now have its start vertex
            int h_clps_prev_pair = pMesh.Halfedges.GetPairHalfedge(h_clps_prev);
            Assert.AreEqual(0, pMesh.Halfedges[h_clps_prev_pair].StartVertex);
        }
예제 #37
0
 public void CanFindHalfedgeUnusedVertices()
 {
     PlanktonMesh pMesh = new PlanktonMesh();
     pMesh.Vertices.Add(0, 0, 0);
     pMesh.Vertices.Add(1, 1, 1);
     // Check for halfedge between v0 and v1
     // In fact, both are unused so we shouldn't find one
     Assert.AreEqual(-1, pMesh.Halfedges.FindHalfedge(0, 1));
 }
예제 #38
0
        public void CanCullUnused()
        {
            // Create a mesh and add some vertices, but don't connect anything to them!
            PlanktonMesh pMesh = new PlanktonMesh();
            pMesh.Vertices.Add(0, 0, 0);
            pMesh.Vertices.Add(1, 1, 1);

            // Cull unused vertices and check count
            pMesh.Vertices.CullUnused();
            Assert.AreEqual(0, pMesh.Vertices.Count);
        }
예제 #39
0
        public void CanAddFacesAroundNonManifoldVertex()
        {
            // a.k.a. the pizza slice test...

            PlanktonMesh pMesh = new PlanktonMesh();

            pMesh.Vertices.Add(0.0, 0.0, 0.0);   // 0 - center
            pMesh.Vertices.Add(-0.5, -0.2, 0.0); // 1 - left/bottom
            pMesh.Vertices.Add(-0.5, 0.2, 0.0);  // 2 - left/top
            pMesh.Vertices.Add(-0.2, 0.5, 0.0);  // 3 - top/left
            pMesh.Vertices.Add(0.2, 0.5, 0.0);   // 4 - top/right
            pMesh.Vertices.Add(0.5, 0.2, 0.0);   // 5 - right/top
            pMesh.Vertices.Add(0.5, -0.2, 0.0);  // 6 - right/bottom

            // Add the first face
            pMesh.Faces.AddFace(2, 1, 0);

            // Check vertex #0 outgoing halfedge index
            Assert.AreEqual(3, pMesh.Vertices[0].OutgoingHalfedge);

            // Add a face which would create a non-manifold condition at vertex #1
            pMesh.Faces.AddFace(0, 4, 3);

            //Assert.AreEqual(12, pMesh.Halfedges.Count);

            // Check that vertex #0 has the expected number of boundary edges
            Assert.AreEqual(4, pMesh.Vertices.NakedEdgeCount(0));

            // Check vertex #0 outgoing halfedge index
            Assert.AreEqual(11, pMesh.Vertices[0].OutgoingHalfedge);

            // Add another face and check again
            pMesh.Faces.AddFace(6, 5, 0);
            Assert.AreEqual(6, pMesh.Vertices.NakedEdgeCount(0));
            Assert.AreEqual(15, pMesh.Vertices[0].OutgoingHalfedge);
            Assert.AreEqual(6, pMesh.Vertices.GetHalfedges(0).Length);

            // Plug a gap - vertex #0 ->outgoing should move
            pMesh.Faces.AddFace(5, 4, 0);
            Assert.AreEqual(4, pMesh.Vertices.NakedEdgeCount(0));
            Assert.IsTrue(pMesh.Halfedges[pMesh.Vertices[0].OutgoingHalfedge].AdjacentFace < 0);
            Assert.AreEqual(6, pMesh.Vertices.GetHalfedges(0).Length);

            // Plug another gap which should make vertex #0 manifold again
            int f = pMesh.Faces.AddFace(0, 3, 2);
            Assert.AreEqual(6, pMesh.Vertices.GetHalfedges(0).Length);
            Assert.AreEqual(2, pMesh.Vertices.NakedEdgeCount(0));

            // Try adding a face which already exits
            f = pMesh.Faces.AddFace(0, 5, 4);
            Assert.AreEqual(-1, f, "Face not added.");
        }
예제 #40
0
        public void CanCollapseAdjacentTriangles()
        {
            // TODO: draw figure here...

            PlanktonMesh pMesh = new PlanktonMesh();

            // Create several vertices
            pMesh.Vertices.Add(0, 3, 0); // 0
            pMesh.Vertices.Add(0, 2, 0); // 1
            pMesh.Vertices.Add(0, 1, 0); // 2
            pMesh.Vertices.Add(1, 3, 0); // 3
            pMesh.Vertices.Add(1, 2, 0); // 4
            pMesh.Vertices.Add(1, 1, 0); // 5
            pMesh.Vertices.Add(1, 0, 0); // 6
            pMesh.Vertices.Add(2, 2, 0); // 7
            pMesh.Vertices.Add(2, 1, 0); // 8

            // Create several faces
            pMesh.Faces.AddFace(0, 1, 4, 3); // 0
            pMesh.Faces.AddFace(1, 2, 5, 4); // 1
            pMesh.Faces.AddFace(3, 4, 7);    // 2
            pMesh.Faces.AddFace(4, 5, 7);    // 3
            pMesh.Faces.AddFace(7, 5, 6, 8); // 4

            // Try to collapse edge between vertices #4 and #7
            int h_clps = pMesh.Halfedges.FindHalfedge(4, 7);
            //int v_keep = pMesh.Halfedges[h_clps].StartVertex;
            int h_succ = pMesh.Halfedges.GetVertexCirculator(h_clps).ElementAt(1);
            Assert.AreEqual(h_succ, pMesh.Halfedges.CollapseEdge(h_clps));

            // Successor to h (around h's start vertex) should now be adjacent to face #4
            Assert.AreEqual(4, pMesh.Halfedges[h_succ].AdjacentFace);

            // Check new vertices of face #4
            Assert.AreEqual(new int[] { 5, 6, 8, 4 }, pMesh.Faces.GetFaceVertices(4));

            // Traverse around mesh boundary and count halfedges
            int count, he_first, he_current;
            count = 0;
            he_first = 1;
            he_current = he_first;
            do
            {
                count++;
                he_current = pMesh.Halfedges[he_current].NextHalfedge;
            }
            while (he_current != he_first);

            Assert.AreEqual(8, count);

            Assert.IsTrue(pMesh.Faces[2].IsUnused && pMesh.Faces[3].IsUnused);
        }
예제 #41
0
 public void CanFindHalfedge()
 {
     // Create a mesh with a single quad face
     PlanktonMesh pMesh = new PlanktonMesh();
     pMesh.Vertices.Add(0, 0, 0);
     pMesh.Vertices.Add(1, 0, 0);
     pMesh.Vertices.Add(1, 1, 0);
     pMesh.Vertices.Add(0, 1, 0);
     pMesh.Faces.AddFace(0, 1, 2, 3);
     // Try and find some halfedges...
     Assert.AreEqual(0, pMesh.Halfedges.FindHalfedge(0, 1));
     Assert.AreEqual(2, pMesh.Halfedges.FindHalfedge(1, 2));
     Assert.AreEqual(-1, pMesh.Halfedges.FindHalfedge(0, 2));
 }
예제 #42
0
파일: FaceTest.cs 프로젝트: uto/Plankton
        public void CannotMergeFacesAntenna()
        {
            PlanktonMesh pMesh = new PlanktonMesh();

            // Create one vertex for each corner of a square
            pMesh.Vertices.Add(0, 0, 0); // 0
            pMesh.Vertices.Add(1, 0, 0); // 1
            pMesh.Vertices.Add(1, 1, 0); // 2
            pMesh.Vertices.Add(0, 1, 0); // 3
            pMesh.Vertices.Add(0.5, 0.5, 0); // 4

            // Create two quadrangular faces
            pMesh.Faces.AddFace(0, 1, 2, 4);
            pMesh.Faces.AddFace(2, 3, 0, 4);

            // Merge should fail (faces are joined by two edges)
            Assert.AreEqual(-1, pMesh.Faces.MergeFaces(4));
        }
예제 #43
0
파일: FaceTest.cs 프로젝트: uto/Plankton
        public void CanCompact()
        {
            PlanktonMesh pMesh = new PlanktonMesh();

            // Create one vertex for each corner of a square
            pMesh.Vertices.Add(0, 0, 0); // 0
            pMesh.Vertices.Add(1, 0, 0); // 1
            pMesh.Vertices.Add(1, 1, 0); // 2
            pMesh.Vertices.Add(0, 1, 0); // 3

            // Create two triangular faces
            pMesh.Faces.AddFace(0, 1, 2);
            pMesh.Faces.AddFace(2, 3, 0);

            // Merge faces and compact (squashing face #0)
            pMesh.Faces.MergeFaces(4);
            pMesh.Faces.CompactHelper();

            // Check some things about the compacted mesh
            Assert.AreEqual(1, pMesh.Faces.Count);
            Assert.AreEqual(new int[] { 0, 1, 2, 3 }, pMesh.Faces.GetFaceVertices(0));
        }
예제 #44
0
파일: FaceTest.cs 프로젝트: uto/Plankton
        public void CanMergeFaces()
        {
            PlanktonMesh pMesh = new PlanktonMesh();

            // Create one vertex for each corner of a square
            pMesh.Vertices.Add(0, 0, 0); // 0
            pMesh.Vertices.Add(1, 0, 0); // 1
            pMesh.Vertices.Add(1, 1, 0); // 2
            pMesh.Vertices.Add(0, 1, 0); // 3

            // Create two triangular faces
            pMesh.Faces.AddFace(0, 1, 2);
            pMesh.Faces.AddFace(2, 3, 0);

            // Force merge to update outgoing halfedge of vertex #2
            pMesh.Vertices[2].OutgoingHalfedge = 4;

            // Merge faces
            int h_rtn = pMesh.Faces.MergeFaces(4);

            // Check that the correct face was retained
            int f = pMesh.Halfedges[h_rtn].AdjacentFace;
            Assert.AreEqual(0, f);

            // Check face halfedges
            int[] fhs = pMesh.Faces.GetHalfedges(f);
            Assert.AreEqual(new int[] { 0, 2, 6, 8 }, fhs);
            foreach (int h in fhs)
            {
                Assert.AreEqual(f, pMesh.Halfedges[h].AdjacentFace);
            }

            // Check that outgoing halfedge of vertex #2 was updated correctly
            Assert.AreEqual(6, pMesh.Vertices[2].OutgoingHalfedge);
            Assert.AreEqual(f, pMesh.Halfedges[6].AdjacentFace);
        }
예제 #45
0
        public void CanSplitVertex()
        {
            // Create a simple non-manifold vertex and split it to make it manifold.

            PlanktonMesh pMesh = new PlanktonMesh();

            // Create 'X' of vertices
            pMesh.Vertices.Add(0, 0, 0); // 0
            pMesh.Vertices.Add(2, 0, 0); // 1
            pMesh.Vertices.Add(2, 2, 0); // 2
            pMesh.Vertices.Add(0, 2, 0); // 3
            pMesh.Vertices.Add(1, 1, 0); // 4 (center)

            pMesh.Faces.AddFace(0, 4, 3);
            pMesh.Faces.AddFace(2, 4, 1);

            // Check we're using the correct halfedges to split vertex #4
            Assert.AreEqual(8, pMesh.Halfedges.FindHalfedge(4, 1));
            Assert.AreEqual(2, pMesh.Halfedges.FindHalfedge(4, 3));

            Assert.AreEqual(7, pMesh.Vertices[4].OutgoingHalfedge);

            // Split vertex #4 (center)
            int h_new = pMesh.Vertices.SplitVertex(8, 2);

            // Check the new halfedge...
            Assert.AreEqual(12, h_new);
            Assert.AreEqual(h_new, pMesh.Halfedges.FindHalfedge(4, 5));

            // Check old vertex
            Assert.AreEqual(1, pMesh.Vertices[4].OutgoingHalfedge);
            Assert.AreEqual(new int[] { 1, 12, 8 }, pMesh.Vertices.GetHalfedges(4));

            // Check new vertex
            Assert.AreEqual(new int[] { 7, 13, 2 }, pMesh.Vertices.GetHalfedges(5));
        }
예제 #46
0
        public void CanCompact()
        {
            PlanktonMesh pMesh = new PlanktonMesh();

            // Create 3x3 grid of vertices
            pMesh.Vertices.Add(0, 2, 0); // 0
            pMesh.Vertices.Add(0, 1, 0); // 1
            pMesh.Vertices.Add(0, 0, 0); // 2
            pMesh.Vertices.Add(1, 2, 0); // 3
            pMesh.Vertices.Add(1, 1, 0); // 4 (center)
            pMesh.Vertices.Add(1, 0, 0); // 5
            pMesh.Vertices.Add(2, 2, 0); // 6
            pMesh.Vertices.Add(2, 1, 0); // 7
            pMesh.Vertices.Add(2, 0, 0); // 8

            // Create four quadrangular faces
            pMesh.Faces.AddFace(0, 1, 4, 3);
            pMesh.Faces.AddFace(3, 4, 7, 6);
            pMesh.Faces.AddFace(1, 2, 5, 4);
            pMesh.Faces.AddFace(4, 5, 8, 7);

            int vertexCount = pMesh.Vertices.Count;

            // Collapse a couple of edges, thus removing two vertices (0 and 2)
            pMesh.Halfedges.CollapseEdge(1);
            pMesh.Halfedges.CollapseEdge(14);

            // Compact vertex list
            pMesh.Vertices.CompactHelper();

            // Check new size of vertex list
            Assert.AreEqual(vertexCount - 2, pMesh.Vertices.Count);

            // Check we can still traverse from vertices correctly (5 used to be 7)
            Assert.AreEqual(new int[] { -1, 3, 1 }, pMesh.Vertices.GetVertexFaces(5));
        }
예제 #47
0
        public void CanEraseCenterVertex()
        {
            // TODO: draw figure here...

            PlanktonMesh pMesh = new PlanktonMesh();

            // Create 3x3 grid of vertices
            pMesh.Vertices.Add(0, 2, 0); // 0
            pMesh.Vertices.Add(0, 1, 0); // 1
            pMesh.Vertices.Add(0, 0, 0); // 2
            pMesh.Vertices.Add(1, 2, 0); // 3
            pMesh.Vertices.Add(1, 1, 0); // 4 (center)
            pMesh.Vertices.Add(1, 0, 0); // 5
            pMesh.Vertices.Add(2, 2, 0); // 6
            pMesh.Vertices.Add(2, 1, 0); // 7
            pMesh.Vertices.Add(2, 0, 0); // 8

            // Create four quadrangular faces
            pMesh.Faces.AddFace(0, 1, 4, 3);
            pMesh.Faces.AddFace(3, 4, 7, 6);
            pMesh.Faces.AddFace(1, 2, 5, 4);
            pMesh.Faces.AddFace(4, 5, 8, 7);

            Assert.AreEqual(4, pMesh.Halfedges[4].StartVertex);
            Assert.AreEqual(0, pMesh.Halfedges[4].AdjacentFace);

            // Erase center vertex
            pMesh.Vertices.EraseCenterVertex(4);

            Assert.IsFalse(pMesh.Faces[0].IsUnused);
            int[] faceHalfedges = pMesh.Faces.GetHalfedges(0);
            int[] expected = new int[] { 6, 0, 14, 16, 20, 22, 10, 12 };
            Assert.AreEqual(8, faceHalfedges.Length);
            Assert.AreEqual(expected, faceHalfedges);
            Assert.AreEqual(-1, pMesh.Vertices[4].OutgoingHalfedge);
        }
예제 #48
0
        public void CanCollapseSameFace(int h)
        {
            //   3-------2
            //   |  f1   |      Tries to collapse the halfedge...
            //   |       |      * 0 - from vertex 1 to vertex 4
            //   |   4   |      * 1 - from vertex 4 to vertex 1
            //   | /   \ |      * 2 - from vertex 4 to vertex 0
            //   |/ f0  \|      * 3 - from vertex 0 to vertex 4
            //   0-------1

            PlanktonMesh mesh = new PlanktonMesh();

            mesh.Vertices.Add(0, 0, 0);     // 0
            mesh.Vertices.Add(100, 0, 0);   // 1
            mesh.Vertices.Add(100, 100, 0); // 2
            mesh.Vertices.Add(0, 100, 0);   // 3
            mesh.Vertices.Add(50, 50, 0);   // 4

            mesh.Faces.AddFace(1, 4, 0);
            mesh.Faces.AddFace(new int[] { 1, 2, 3, 0, 4 });

            mesh.Halfedges.CollapseEdge(h);

            Assert.IsTrue(mesh.Faces[0].IsUnused, "face 0 should be unset");
            Assert.AreEqual(4, mesh.Faces.GetFaceVertices(1).Length, "face 1 should have 4 vertices");
        }
예제 #49
0
        public void CanCollapseValenceThreeVertex()
        {
            PlanktonMesh pMesh = new PlanktonMesh();

            // Create mesh with one triangular face
            pMesh.Vertices.Add(0, 0, 0); // 0
            pMesh.Vertices.Add(2, 0, 0); // 1
            pMesh.Vertices.Add(1, 1.4, 0); // 2
            pMesh.Faces.AddFace(0, 1, 2);
            
            // create vertex at center and get a halfedge pointing *towards* it
            int v = pMesh.Faces.Stellate(0);
            int h = pMesh.Vertices.GetIncomingHalfedge(v);

            // count faces before collapse
            Assert.AreEqual(3, pMesh.Faces.Count);

            // attempt to collapse one of the internal edges
            Assert.GreaterOrEqual(0, pMesh.Halfedges.CollapseEdge(h));

            // there should be 6 unused halfedges now...
            Assert.AreEqual(6, pMesh.Halfedges.Where(q => q.IsUnused).Count());

            // compact and count faces again
            pMesh.Compact();
            Assert.AreEqual(1, pMesh.Faces.Count);
        }
예제 #50
0
        public void CanCompact()
        {
            PlanktonMesh pMesh = new PlanktonMesh();

            // Create vertices in 3x2 grid
            pMesh.Vertices.Add(0, 0, 0); // 0
            pMesh.Vertices.Add(1, 0, 0); // 1
            pMesh.Vertices.Add(1, 1, 0); // 2
            pMesh.Vertices.Add(0, 1, 0); // 3
            pMesh.Vertices.Add(2, 0, 0); // 4
            pMesh.Vertices.Add(2, 1, 0); // 5

            // Create two quadrangular faces
            pMesh.Faces.AddFace(0, 1, 2, 3);
            pMesh.Faces.AddFace(1, 4, 5, 2);

            // Remove the first face and compact
            pMesh.Faces.RemoveFace(0);
            pMesh.Vertices.CullUnused();
            pMesh.Compact();

            // Check some things about the compacted mesh
            Assert.AreEqual(4, pMesh.Vertices.Count);
            Assert.AreEqual(1, pMesh.Faces.Count);
            Assert.AreEqual(8, pMesh.Halfedges.Count);
            Assert.AreEqual(new int[] { 0, 2, 3, 1 }, pMesh.Faces.GetFaceVertices(0));
        }
예제 #51
0
        public void CanCollapseInternalEdge()
        {
            PlanktonMesh pMesh = new PlanktonMesh();

            // Create a three-by-three grid of vertices
            pMesh.Vertices.Add(-0.5, -0.5, 0.0); // 0
            pMesh.Vertices.Add(-0.5, 0.0, 0.0);  // 1
            pMesh.Vertices.Add(-0.5, 0.5, 0.0);  // 2
            pMesh.Vertices.Add(0.0, -0.5, 0.0);  // 3
            pMesh.Vertices.Add(0.0, 0.0, 0.0);   // 4
            pMesh.Vertices.Add(0.0, 0.5, 0.0);   // 5
            pMesh.Vertices.Add(0.5, -0.5, 0.0);  // 6
            pMesh.Vertices.Add(0.5, 0.0, 0.0);   // 7
            pMesh.Vertices.Add(0.5, 0.5, 0.0);   // 8

            // Create four quadrangular faces
            pMesh.Faces.AddFace(1, 4, 5, 2);
            pMesh.Faces.AddFace(0, 3, 4, 1);
            pMesh.Faces.AddFace(4, 7, 8, 5);
            pMesh.Faces.AddFace(3, 6, 7, 4);

            Assert.AreEqual(4, pMesh.Faces.Count);

            int h_clps = pMesh.Vertices[4].OutgoingHalfedge;
            int v_suc = pMesh.Vertices.GetHalfedges(4)[1];
            int h_boundary = pMesh.Vertices[3].OutgoingHalfedge;

            // Collapse center vertex's outgoing halfedge
            int h_rtn = pMesh.Halfedges.CollapseEdge(h_clps);

            // Check that center vertex's outgoing halfedge has been updated
            Assert.AreEqual(h_boundary, pMesh.Vertices[4].OutgoingHalfedge);

            // Edge collapse should return successor around start vertex
            Assert.AreEqual(v_suc, h_rtn);

            // Check for closed loops (without collapsed halfedge)
            Assert.AreEqual(4, pMesh.Faces.GetHalfedges(0).Length);
            Assert.AreEqual(3, pMesh.Faces.GetHalfedges(1).Length);
            Assert.AreEqual(4, pMesh.Faces.GetHalfedges(2).Length);
            Assert.AreEqual(3, pMesh.Faces.GetHalfedges(3).Length);

            // Check no halfedges reference removed vertex (#7)
            for (int h = 0; h < pMesh.Halfedges.Count; h++)
            {
                if (h == h_clps || h == pMesh.Halfedges.GetPairHalfedge(h_clps))
                    continue; // Skip removed halfedges
                Assert.AreNotEqual(3, pMesh.Halfedges[h].StartVertex);
            }
        }
예제 #52
0
        public void CanTruncateMesh()
        {
            // Create a simple cube

            PlanktonMesh pMesh = new PlanktonMesh();

            pMesh.Vertices.Add(-0.5, -0.5, 0.5);
            pMesh.Vertices.Add(-0.5, -0.5, -0.5);
            pMesh.Vertices.Add(-0.5, 0.5, -0.5);
            pMesh.Vertices.Add(-0.5, 0.5, 0.5);
            pMesh.Vertices.Add(0.5, -0.5, 0.5);
            pMesh.Vertices.Add(0.5, -0.5, -0.5);
            pMesh.Vertices.Add(0.5, 0.5, -0.5);
            pMesh.Vertices.Add(0.5, 0.5, 0.5);

            pMesh.Faces.AddFace(3, 2, 1, 0);
            pMesh.Faces.AddFace(1, 5, 4, 0);
            pMesh.Faces.AddFace(2, 6, 5, 1);
            pMesh.Faces.AddFace(7, 6, 2, 3);
            pMesh.Faces.AddFace(4, 7, 3, 0);
            pMesh.Faces.AddFace(5, 6, 7, 4);

            Assert.AreEqual(6, pMesh.Faces.Count);

            var tMesh = pMesh.TruncateVertices();

            Assert.AreEqual(pMesh.Faces.Count + pMesh.Vertices.Count, tMesh.Faces.Count);

            // TODO: geometrical check
        }
예제 #53
0
        public void CanCollapseValenceThreeVertex()
        {
            // Create five faces and collapse diagonal edge
            // (halfedge {4->8} - valence three vertex at end)
            //
            // 0---3---6
            // |   |   |
            // |   |   |
            // 1-- 4---7
            // |   |\  |
            // |   |  \|
            // 2---5---8

            PlanktonMesh pMesh = new PlanktonMesh();

            // Create mesh with one triangular face
            pMesh.Vertices.Add(0, 0, 0); // 0
            pMesh.Vertices.Add(2, 0, 0); // 1
            pMesh.Vertices.Add(1, 1.4, 0); // 2
            pMesh.Faces.AddFace(0, 1, 2);

            pMesh.Faces.Stellate(0);
            int h = pMesh.Vertices.GetIncomingHalfedge(3);

            Assert.AreEqual(3, pMesh.Faces.Count);

            Assert.GreaterOrEqual(0, pMesh.Halfedges.CollapseEdge(h));

            pMesh.Compact();

            Assert.AreEqual(1, pMesh.Faces.Count);
        }
예제 #54
0
        public void CanFlipEdge()
        {
            // Create a triangulated grid and flip one of the edges.
            //
            //    Before  >>>  After
            //
            //   2---5---8   2---5-
            //   |\  |  /|   |  /|
            //   | \ | / |   | / |
            //   |  \|/  |   |/  |/
            //   1---4---7   1---4-
            //   |  /|\  |   |  /|\
            //   | / | \ |
            //   |/  |  \|        (etc.)
            //   0---3---6
            //

            PlanktonMesh pMesh = new PlanktonMesh();

            pMesh.Vertices.Add(-0.5, -0.5, 0.0); // 0
            pMesh.Vertices.Add(-0.5, 0.0, 0.0);  // 1
            pMesh.Vertices.Add(-0.5, 0.5, 0.0);  // 2
            pMesh.Vertices.Add(0.0, -0.5, 0.0);  // 3
            pMesh.Vertices.Add(0.0, 0.0, 0.0);   // 4
            pMesh.Vertices.Add(0.0, 0.5, 0.0);   // 5
            pMesh.Vertices.Add(0.5, -0.5, 0.0);  // 6
            pMesh.Vertices.Add(0.5, 0.0, 0.0);   // 7
            pMesh.Vertices.Add(0.5, 0.5, 0.0);   // 8

            pMesh.Faces.AddFace(4, 1, 0); // 0
            pMesh.Faces.AddFace(4, 0, 3); // 1
            pMesh.Faces.AddFace(4, 3, 6); // 2
            pMesh.Faces.AddFace(4, 6, 7); // 3
            pMesh.Faces.AddFace(4, 7, 8); // 4
            pMesh.Faces.AddFace(4, 8, 5); // 5
            pMesh.Faces.AddFace(4, 5, 2); // 6
            pMesh.Faces.AddFace(4, 2, 1); // 7

            // Find the outgoing halfedge of Vertex #4 (center)

            int he = pMesh.Vertices[4].OutgoingHalfedge;

            Assert.AreEqual(29, he);

            Assert.IsTrue(pMesh.Halfedges.FlipEdge(he));

            // Check vertices for each face
            Assert.AreEqual(new int[]{ 1, 5, 2 }, pMesh.Faces.GetFaceVertices(6));
            Assert.AreEqual(new int[]{ 5, 1, 4 }, pMesh.Faces.GetFaceVertices(7));

            // Check outgoing he of Vertex #4 has been updated
            he = pMesh.Vertices[4].OutgoingHalfedge;
            Assert.AreNotEqual(29, he, "Vertex #4 should not be linked to Halfedge #29 post-flip");
            Assert.AreEqual(25, he);

            // Check adjacent face in each interior halfedge is correct
            foreach (int h in pMesh.Faces.GetHalfedges(0))
            {
                Assert.AreEqual(0, pMesh.Halfedges[h].AdjacentFace);
            }
            foreach (int h in pMesh.Faces.GetHalfedges(1))
            {
                Assert.AreEqual(1, pMesh.Halfedges[h].AdjacentFace);
            }

            // Check halfedges for each vertex
            if (pMesh.Vertices.GetHalfedges(4).Contains(29))
                Assert.Fail("Vertex #4 should not be linked to Halfedge #29 post-flip");
            if (pMesh.Vertices.GetHalfedges(2).Contains(28))
                Assert.Fail("Vertex #2 should not be linked to Halfedge #28 post-flip");
            Assert.Contains(29, pMesh.Vertices.GetHalfedges(5),
                            "Vertex #5 should now be linked to Halfedge #29");
            Assert.Contains(28, pMesh.Vertices.GetHalfedges(1),
                            "Vertex #1 should now be linked to Halfedge #28");
        }
예제 #55
0
        public void CanDualCube()
        {
            // Create a simple cube

            PlanktonMesh pMesh = new PlanktonMesh();

            pMesh.Vertices.Add(-0.5, -0.5, 0.5);
            pMesh.Vertices.Add(-0.5, -0.5, -0.5);
            pMesh.Vertices.Add(-0.5, 0.5, -0.5);
            pMesh.Vertices.Add(-0.5, 0.5, 0.5);
            pMesh.Vertices.Add(0.5, -0.5, 0.5);
            pMesh.Vertices.Add(0.5, -0.5, -0.5);
            pMesh.Vertices.Add(0.5, 0.5, -0.5);
            pMesh.Vertices.Add(0.5, 0.5, 0.5);

            pMesh.Faces.AddFace(3, 2, 1, 0);
            pMesh.Faces.AddFace(1, 5, 4, 0);
            pMesh.Faces.AddFace(2, 6, 5, 1);
            pMesh.Faces.AddFace(7, 6, 2, 3);
            pMesh.Faces.AddFace(4, 7, 3, 0);
            pMesh.Faces.AddFace(5, 6, 7, 4);

            var dual = pMesh.Dual();

            Assert.AreEqual(new int[] { 2, 3, 0, 1 }, dual.Vertices.GetVertexFaces(0));
        }
예제 #56
0
        public void CanCreateCubeFromFaceVertex()
        {
            // Create a simple cube

            PlanktonMesh pMesh = new PlanktonMesh();

            pMesh.Vertices.Add(-0.5, -0.5, 0.5);
            pMesh.Vertices.Add(-0.5, -0.5, -0.5);
            pMesh.Vertices.Add(-0.5, 0.5, -0.5);
            pMesh.Vertices.Add(-0.5, 0.5, 0.5);
            pMesh.Vertices.Add(0.5, -0.5, 0.5);
            pMesh.Vertices.Add(0.5, -0.5, -0.5);
            pMesh.Vertices.Add(0.5, 0.5, -0.5);
            pMesh.Vertices.Add(0.5, 0.5, 0.5);

            pMesh.Faces.AddFace(3, 2, 1, 0);
            pMesh.Faces.AddFace(1, 5, 4, 0);
            pMesh.Faces.AddFace(2, 6, 5, 1);
            pMesh.Faces.AddFace(7, 6, 2, 3);
            pMesh.Faces.AddFace(4, 7, 3, 0);
            pMesh.Faces.AddFace(5, 6, 7, 4);

            Assert.AreEqual(24, pMesh.Halfedges.Count);

            // Check that half-edges have been linked up correctly
            // TODO: Add individual unit tests to verify the methods used below

            // Get all outgoing halfedges from vertex #0 and compare against expected
            int[] vertexZeroHalfedges = pMesh.Vertices.GetHalfedges(0);
            int[] vertexZeroHalfedgesExpected = new int[]{ 13, 5, 6 };
            Assert.AreEqual(3, vertexZeroHalfedges.Length);
            foreach (int halfedge in vertexZeroHalfedgesExpected)
            {
                Assert.Contains(halfedge, vertexZeroHalfedges);
            }
            // Check that none of these edges are on a boundary (closed mesh)
            Assert.AreEqual(0, pMesh.Vertices.NakedEdgeCount(0));

            // Get all halfedges from face #2 and compare against expected
            int[] faceTwoHalfedges = pMesh.Faces.GetHalfedges(2);
            int[] faceTwoHalfedgesExpected = new int[]{ 14, 16, 9, 3 };
            Assert.AreEqual(4, faceTwoHalfedges.Length);
            foreach (int halfedge in faceTwoHalfedgesExpected)
            {
                Assert.Contains(halfedge, faceTwoHalfedges);
            }
            // Check that none of these edges are on a boundary (closed mesh)
            Assert.AreEqual(0, pMesh.Faces.NakedEdgeCount(2));

            // Get all vertices from face #4 and compare against expected
            int[] faceFourVertices = pMesh.Faces.GetFaceVertices(4);
            int[] faceFourVerticesExpected = new int[]{ 4, 7, 3, 0 };
            Assert.AreEqual(faceFourVerticesExpected, faceFourVertices);

            // Get all faces from vertex #1 and compare against expected
            int[] vertexOneFaces = pMesh.Vertices.GetVertexFaces(1);
            int[] vertexOneFacesExpected = new int[]{ 0, 1, 2 };
            Assert.AreEqual(3, vertexOneFaces.Length);
            foreach (int face in vertexOneFacesExpected)
            {
                Assert.Contains(face, vertexOneFaces);
            }

            // Get all vertex neighbours from vertex #0 and compare against expected
            int[] vertexZeroNeighbours = pMesh.Vertices.GetVertexNeighbours(0);
            int[] vertexZeroNeighboursExpected = new int[]{ 4, 1, 3 };
            Assert.AreEqual(3, vertexZeroNeighbours.Length);
            foreach (int vertex in vertexZeroNeighboursExpected)
            {
                Assert.Contains(vertex, vertexZeroNeighbours);
            }

            // Check that halfedges exist where they are expected to
            Assert.AreEqual(13, pMesh.Halfedges.FindHalfedge(0, 4)); // exists
            Assert.AreEqual(-1, pMesh.Halfedges.FindHalfedge(1, 3)); // doesn't exist
        }
예제 #57
0
        public void CannotCollapseNonManifoldEdge()
        {
            PlanktonMesh pMesh = new PlanktonMesh();

            // Create vertices in 3x2 grid
            pMesh.Vertices.Add(-1, 0, 0); // 0
            pMesh.Vertices.Add(0, -1, 0); // 1
            pMesh.Vertices.Add(1, 0, 0);  // 2
            pMesh.Vertices.Add(0, 1, 0);  // 3
            pMesh.Vertices.Add(-1, -2, 0); // 4
            pMesh.Vertices.Add(0, -3, 0);  // 5
            pMesh.Vertices.Add(1, -2, 0);  // 6

            // Create several triangular faces
            pMesh.Faces.AddFace(0, 1, 3);
            pMesh.Faces.AddFace(1, 2, 3);
            pMesh.Faces.AddFace(0, 4, 1);
            pMesh.Faces.AddFace(4, 5, 1);
            // And one quad face
            pMesh.Faces.AddFace(1, 5, 6, 2);

            pMesh.Faces.Stellate(0);
            pMesh.Faces.Stellate(1);

            Assert.AreEqual(9, pMesh.Faces.Count);

            Assert.AreEqual(-1, pMesh.Halfedges.CollapseEdge(2));
            Assert.AreEqual(-1, pMesh.Halfedges.CollapseEdge(6));
        }
예제 #58
0
        public void CanSplitEdge()
        {
            PlanktonMesh pMesh = new PlanktonMesh();
            var hs = pMesh.Halfedges;

            // Create one vertex for each corner of a square
            pMesh.Vertices.Add(0, 0, 0); // 0
            pMesh.Vertices.Add(1, 0, 0); // 1
            pMesh.Vertices.Add(1, 1, 0); // 2
            pMesh.Vertices.Add(0, 1, 0); // 3

            // Create two triangular faces
            pMesh.Faces.AddFace(0, 1, 2);
            pMesh.Faces.AddFace(2, 3, 0);

            // Change outgoing of vert #2 so that we can check it updates
            pMesh.Vertices[2].OutgoingHalfedge = 4;

            // Split the diagonal edge
            int split_he = 5; // he from v #0 to #2
            int new_he = hs.SplitEdge(split_he);

            // Returned halfedge should start at the new vertex
            Assert.AreEqual(4, hs[new_he].StartVertex);

            // Check that the 4 halfedges are all in the right places...
            // New ones are between new vertex and second vertex
            Assert.AreEqual(new_he, hs.FindHalfedge(4, 2));
            Assert.AreEqual(hs.GetPairHalfedge(new_he), hs.FindHalfedge(2, 4));
            // Existing ones are now between first vertex and new vertex
            Assert.AreEqual(split_he, hs.FindHalfedge(0, 4));
            Assert.AreEqual(hs.GetPairHalfedge(split_he), hs.FindHalfedge(4, 0));

            // New halfedges should have the same faces as the existing ones next to them
            Assert.AreEqual(hs[split_he].AdjacentFace, hs[new_he].AdjacentFace);
            Assert.AreEqual(hs[hs.GetPairHalfedge(split_he)].AdjacentFace,
                            hs[hs.GetPairHalfedge(new_he)].AdjacentFace);

            // New vertex's outgoing should be returned halfedge
            Assert.AreEqual(new_he, pMesh.Vertices[4].OutgoingHalfedge);

            // New vertex should be 2-valent
            Assert.AreEqual(2, pMesh.Vertices.GetHalfedges(4).Length);

            // Check existing vertices...
            Assert.AreEqual(new int[] {9, 5, 0}, pMesh.Vertices.GetHalfedges(0));
            Assert.AreEqual(new int[] {11, 6, 3}, pMesh.Vertices.GetHalfedges(2));
        }
예제 #59
0
        public void CannotTraverseUnusedHalfedge()
        {
            PlanktonMesh pMesh = new PlanktonMesh();
            pMesh.Halfedges.Add(PlanktonHalfedge.Unset);
            pMesh.Halfedges.Add(PlanktonHalfedge.Unset);

            // You shouldn't be able to enumerate a circulator for either of these unset halfedges
            Assert.Throws<InvalidOperationException>(() => pMesh.Halfedges.GetFaceCirculator(0).ToArray());
            Assert.Throws<InvalidOperationException>(
                delegate { foreach (int h in pMesh.Halfedges.GetVertexCirculator(1)) {} } );
        }
예제 #60
0
        public void CannotCollapseNonManifoldVertex()
        {
            PlanktonMesh pMesh = new PlanktonMesh();

            // Create vertices in 3x2 grid
            pMesh.Vertices.Add(0, 0, 0); // 0
            pMesh.Vertices.Add(1, 0, 0); // 1
            pMesh.Vertices.Add(1, 1, 0); // 2
            pMesh.Vertices.Add(0, 1, 0); // 3
            pMesh.Vertices.Add(2, 0, 0); // 4
            pMesh.Vertices.Add(2, 1, 0); // 5

            // Create two quadrangular faces
            pMesh.Faces.AddFace(0, 1, 2, 3);
            pMesh.Faces.AddFace(1, 4, 5, 2);

            // Try to collapse edge between vertices #1 and #2
            // (which would make vertex #1 non-manifold)
            int h = pMesh.Halfedges.FindHalfedge(1, 2);
            Assert.AreEqual(-1, pMesh.Halfedges.CollapseEdge(h));

            // That's right, you can't!
        }