/// <summary>
        /// Add a new vertex to the field, breaking existing triangles as necessary.
        /// </summary>
        /// <param name="vtx">Position of the new vertex to add.</param>
        private void AddVertexSubdividing(Vector3 vtx)
        {
            vertices.Add(vtx);
            int newVertIdx = vertices.Count - 1;

            // Find closest triangle
            IndexedBary bary = FindTriangle(vtx);

            Debug.Assert(bary.bary.IsInterior, "Should be contained by background seed vertices.");

            // Find closest edge
            Edge edge = ClosestEdge(bary);

            // Find any other triangle with that edge
            int oppositieTriIdx = FindTriangleWithEdge(edge, bary.triangle);

            bool canSplit = CanSplit(edge, oppositieTriIdx, newVertIdx);

            if (canSplit)
            {
                AddVertexSplitEdge(edge, bary.triangle, oppositieTriIdx, newVertIdx);
            }
            else
            {
                AddVertexMidTriangle(bary.triangle, newVertIdx);
            }
        }
        /// <summary>
        /// Brute force search to find a triangle that the query position projects onto.
        /// </summary>
        /// <param name="pos">The query position.</param>
        /// <returns>The triangle projected onto, with interpolation information.</returns>
        /// <remarks>
        /// Note the returned value is never null. Also, if there is any data to query (Add() has been
        /// called with a vertex list of length > 0), then the returned value.bary will also be non-null
        /// and valid.
        /// However, if there is no data to query, then returned_value.bary will be null.
        /// </remarks>
        private IndexedBary FindTriangle(Vector3 pos)
        {
            IndexedBary bary = new IndexedBary();

            bary.bary = new Interpolant();
            for (int i = 0; i < triangles.Count; ++i)
            {
                Triangle tri = triangles[i];
                Vector3  p0  = vertices[tri.idx0];
                p0.y = 0;
                Vector3 p1 = vertices[tri.idx1];
                p1.y = 0;
                Vector3 p2 = vertices[tri.idx2];
                p2.y = 0;
                /// Note area will be negative, because this is xz, not xy, but that will cancel with the negative cross products below.
                float area = Vector3.Cross(p2 - p1, p0 - p1).y;
                if (area >= 0)
                {
                    area = 0;
                }
                Debug.Assert(area < 0, "Degenerate triangle in Find");

                Vector3 ps = new Vector3(pos.x, 0, pos.z);

                bary.bary.weights[0] = Vector3.Cross(p2 - p1, ps - p1).y / area;
                bary.bary.weights[1] = Vector3.Cross(p0 - p2, ps - p2).y / area;
                bary.bary.weights[2] = Vector3.Cross(p1 - p0, ps - p0).y / area;

                if (bary.bary.IsInterior)
                {
                    bary.triangle    = i;
                    bary.bary.idx[0] = tri.idx0;
                    bary.bary.idx[1] = tri.idx1;
                    bary.bary.idx[2] = tri.idx2;

                    return(bary);
                }
            }
            Debug.Assert(false, "Found no triangle for which this position is interior.");
            bary.bary = null;
            return(bary);
        }
        /// <summary>
        /// Find the edge closest to the interpolation point, or equivalently the edge opposite the
        /// vertex with the weakest influence.
        /// </summary>
        /// <param name="bary">The triangular interpolation.</param>
        /// <returns>Edge data for strongest edge.</returns>
        private Edge ClosestEdge(IndexedBary bary)
        {
            Triangle tri = triangles[bary.triangle];
            Edge     edge;

            edge.idx0 = tri.idx1;
            edge.idx1 = tri.idx2;
            float minWeight = bary.bary.weights[0];

            if (bary.bary.weights[1] < minWeight)
            {
                edge.idx0 = tri.idx0;
                edge.idx1 = tri.idx2;
                minWeight = bary.bary.weights[1];
            }
            if (bary.bary.weights[2] < minWeight)
            {
                edge.idx0 = tri.idx0;
                edge.idx1 = tri.idx1;
            }
            return(edge);
        }