public MeshGraph Clone()
        {
            MeshGraph mg = new MeshGraph();

            mg.triangles = this.triangles;

            foreach (MeshVertex v in vertices)
            {
                MeshVertex new_v = new MeshVertex(v.Position);
                new_v.SetGraphInfo(mg, mg.vertices.Count);
                mg.vertices.Add(new_v);
            }

            foreach (MeshEdge e in edges)
            {
                MeshEdge new_e = new MeshEdge(mg.Eqv(e.V1), mg.Eqv(e.V2));
                new_e.SetGraphInfo(mg, mg.edges.Count);
                mg.edges.Add(new_e);
            }

            foreach (MeshFacet f in facets)
            {
                MeshFacet new_f = new MeshFacet();
                foreach (MeshVertex v in f.vertices)
                {
                    new_f.vertices.Add(mg.Eqv(v));
                }
                new_f.SetGraphInfo(mg, mg.facets.Count);
                mg.facets.Add(new_f);
            }

            // Maintain adjacency cache
            foreach (MeshEdge e in mg.edges)
            {
                MeshEdge old_e = this.Eqv(e);
                e.f1 = mg.Eqv(old_e.f1);
                e.f2 = mg.Eqv(old_e.f2);
            }

            foreach (MeshVertex v in mg.vertices)
            {
                MeshVertex old_v = this.Eqv(v);
                foreach (var entry in old_v.adjacency)
                {
                    v.adjacency.Add(mg.Eqv(entry.Key), mg.Eqv(entry.Value));
                }
            }

            return(mg);
        }
        public MeshFacet AddFacet(params MeshVertex[] vs)
        {
            if (vs.Length < 3)
            {
                throw new Exception("Vertex count less than 3.");
            }
            for (int vi = 0; vi < vs.Length; vi++)
            {
                if (vs[vi] == vs[(vi + 1) % vs.Length])
                {
                    throw new Exception("Ill-formed vertex sequence");
                }
            }

            MeshFacet f = new MeshFacet(vs);

            string failure = "";

            for (int vi = 0; vi < vs.Length; vi++)
            {
                MeshVertex p1 = vs[vi];
                MeshVertex p2 = vs[(vi + 1) % vs.Length];

                MeshEdge e = AddEdge(p1, p2);

                if (e.V1 == p1 && e.V2 == p2)
                {
                    if (e.f1 != null)
                    {
                        failure = "Positive facet has been occupied";
                        break;
                    }
                    e.f1 = f;
                }
                else if (e.V1 == p2 && e.V2 == p1)
                {
                    if (e.f2 != null)
                    {
                        failure = "Negative facet has been occupied";
                        break;
                    }
                    e.f2 = f;
                }
                else
                {
                    throw new Exception("Unexpected edge");
                }
            }

            // rollback
            if (failure.Length > 0)
            {
                foreach (MeshEdge e in f.Edges)
                {
                    if (e == null)
                    {
                        continue;
                    }
                    if (e.f1 == f)
                    {
                        e.f1 = null;
                    }
                    if (e.f2 == f)
                    {
                        e.f2 = null;
                    }
                }
                throw new Exception(failure);
            }

            int i = facets.Count;

            facets.Add(f);
            f.SetGraphInfo(this, i);

            triangles += f.TrianglesCount;

            return(f);
        }