public override bool Equals(object obj)
        {
            TriangleEdge other = obj as TriangleEdge;

            if (other != null)
            {
                return((a == other.a && b == other.b) || (a == other.b && b == other.a));
            }
            return(false);
        }
        /**
         * Compute the normal of the border edge.
         * */
        private Vector3 ComputeBorderEdgeNormal(TriangleEdge edge, ITriangleMesh mesh)
        {
            Vector3 v0 = mesh.GetVertex(edge.A);
            Vector3 v1 = mesh.GetVertex(edge.B);
            Vector3 e  = Vector3.Subtract(v1, v0);
            Vector3 n  = Vector3.Cross(e, Vector3.UnitZ);

            n.Normalize();
            return(n);
        }
        /*
         * Create the VBO for the border
         * */
        void CreateBorderVBO()
        {
            borderVBO = new VertexBufferObject();
            List <TriangleEdge> borderEdges = mesh.GetBorder();
            Color4 borderColor = Color4.Pink;
            List <RenderVertex> renderVertices = new List <RenderVertex>();

            for (int i = 0; i < borderEdges.Count; i++)
            {
                TriangleEdge edge = borderEdges[i];
                Vector3      a    = mesh.GetVertex(edge.A);
                Vector3      b    = mesh.GetVertex(edge.B);
                renderVertices.Add(new RenderVertex(a, new Vector3(0, 1, 0), borderColor));
                renderVertices.Add(new RenderVertex(b, new Vector3(0, 1, 0), borderColor));
            }
            borderVBO.Setup(renderVertices, PrimitiveType.Lines);
        }
        private ITriangleMesh CreateBoundary(ITriangleMesh mesh, float height, float borderHeightTop, float borderHeightBottom, Vector3 offset, Vector2[] cornerTexCoords)
        {
            List <TriangleEdge> border       = mesh.GetBorder();
            int           vertsPerBorderEdge = 3;
            ITriangleMesh borderMesh         = new TriangleMesh();

            for (int i = 0; i < border.Count; i++)
            {
                borderMesh.AddVertex(mesh.GetVertex(border[i].A));
            }
            for (int i = 0; i < border.Count; i++)
            {
                TriangleEdge borderEdge = border[i];
                TriangleEdge prevEdge   = border[(i + border.Count - 1) % border.Count];
                Vector3      v          = borderMesh.GetVertex(i);

                // v0
                Vector3 edgeNormal     = ComputeBorderEdgeNormal(borderEdge, mesh);
                Vector3 prevEdgeNormal = ComputeBorderEdgeNormal(prevEdge, mesh);
                Vector3 borderNormal   = Vector3.Add(edgeNormal, prevEdgeNormal);
                borderNormal.Normalize();
                borderNormal = Vector3.Multiply(borderNormal, Math.Max(borderHeightTop, borderHeightBottom) / (float)Math.Sin(30.0 / 180.0 * Math.PI));
                Vector3 v0 = Vector3.Add(Vector3.Add(v, borderNormal), new Vector3(0, 0, -borderHeightTop));
                borderMesh.AddVertex(v0);

                // v1
                Vector3 v1 = Vector3.Add(v0, Vector3.Multiply(Vector3.UnitZ, -(height - (borderHeightTop + borderHeightBottom))));
                borderMesh.AddVertex(v1);

                // v2
                Vector3 v2 = Vector3.Add(v, Vector3.Multiply(Vector3.UnitZ, -height));
                borderMesh.AddVertex(v2);
            }

            float alpha = (float)(borderHeightTop * Math.Sqrt(2) / (borderHeightTop * Math.Sqrt(2) + borderHeightBottom * Math.Sqrt(2) + height));
            float beta  = 1 - (float)(borderHeightBottom * Math.Sqrt(2) / (borderHeightTop * Math.Sqrt(2) + borderHeightBottom * Math.Sqrt(2) + height));
            int   ti0   = borderMesh.AddTextureCoordinate(cornerTexCoords[0]);
            int   ti1   = borderMesh.AddTextureCoordinate(Vector2.Add(Vector2.Multiply(cornerTexCoords[0], 1 - alpha), Vector2.Multiply(cornerTexCoords[1], alpha)));
            int   ti2   = borderMesh.AddTextureCoordinate(Vector2.Add(Vector2.Multiply(cornerTexCoords[0], 1 - beta), Vector2.Multiply(cornerTexCoords[1], beta)));
            int   ti3   = borderMesh.AddTextureCoordinate(cornerTexCoords[1]);
            int   ti_0  = borderMesh.AddTextureCoordinate(cornerTexCoords[2]);
            int   ti_1  = borderMesh.AddTextureCoordinate(Vector2.Add(Vector2.Multiply(cornerTexCoords[2], 1 - alpha), Vector2.Multiply(cornerTexCoords[3], alpha)));
            int   ti_2  = borderMesh.AddTextureCoordinate(Vector2.Add(Vector2.Multiply(cornerTexCoords[2], 1 - beta), Vector2.Multiply(cornerTexCoords[3], beta)));
            int   ti_3  = borderMesh.AddTextureCoordinate(cornerTexCoords[3]);

            // Triangles
            for (int i = 0; i < border.Count; i++)
            {
                TriangleEdge borderEdge = border[i];
                int          vi0        = border.Count + vertsPerBorderEdge * i + 0;
                int          vi1        = border.Count + vertsPerBorderEdge * i + 1;
                int          vi2        = border.Count + vertsPerBorderEdge * i + 2;
                int          vi_0       = border.Count + vertsPerBorderEdge * ((i + 1) % border.Count) + 0;
                int          vi_1       = border.Count + vertsPerBorderEdge * ((i + 1) % border.Count) + 1;
                int          vi_2       = border.Count + vertsPerBorderEdge * ((i + 1) % border.Count) + 2;
                // A
                Triangle t = new Triangle(i, vi0, (i + 1) % border.Count, ti0, ti1, ti_1);
                borderMesh.AddTriangle(t);
                // B
                t = new Triangle((i + 1) % border.Count, vi0, vi_0, ti_0, ti1, ti_1);
                borderMesh.AddTriangle(t);
                // C
                t = new Triangle(vi0, vi1, vi_0, ti1, ti2, ti_1);
                borderMesh.AddTriangle(t);
                // D
                t = new Triangle(vi1, vi_1, vi_0, ti2, ti_2, ti_1);
                borderMesh.AddTriangle(t);
                // E
                t = new Triangle(vi1, vi2, vi_1, ti2, ti3, ti_2);
                borderMesh.AddTriangle(t);
                // F
                t = new Triangle(vi2, vi_2, vi_1, ti3, ti_3, ti_2);
                borderMesh.AddTriangle(t);
            }

            return(borderMesh);
        }
        public List <TriangleEdge> GetBorder()
        {
            List <TriangleEdge> border = new List <TriangleEdge>();

            foreach (Triangle t in triangles)
            {
                for (int i = 0; i < 3; i++)
                {
                    TriangleEdge e = new TriangleEdge(t.GetVertexIndex(i), t.GetVertexIndex((i + 1) % 3));
                    if (!border.Contains(e))
                    {
                        border.Add(e);
                    }
                    else
                    {
                        border.Remove(e);
                    }
                }
            }
            Console.WriteLine("Mesh border: " + border.Count + " edges.");

            // Sort
            List <TriangleEdge> sortedBorder = new List <TriangleEdge>();

            while (border.Count > 0)
            {
                TriangleEdge start = border[0];
                sortedBorder.Add(start);
                border.Remove(start);

                int  endIdx         = start.B;
                bool found          = true;
                int  borderPolySize = 1;
                while (found)
                {
                    found = false;
                    for (int i = 0; i < border.Count; i++)
                    {
                        TriangleEdge e = border[i];
                        if (e.A == endIdx)
                        {
                            sortedBorder.Add(e);
                            border.Remove(e);
                            endIdx = e.B;
                            found  = true;
                            borderPolySize++;
                        }
                        else if (e.B == endIdx)
                        {
                            sortedBorder.Add(e);
                            border.Remove(e);
                            e.Flip();
                            endIdx = e.A;
                            found  = true;
                            borderPolySize++;
                        }
                    }
                }

                Console.WriteLine("Border polygon found: " + ((start.A == sortedBorder[sortedBorder.Count - 1].B) ? "closed" : "open") + ", " + borderPolySize + " edges");
            }
            return(sortedBorder);
        }