/// <summary>
        /// Creates a thread-safe, fully validated builder.
        /// </summary>
        /// <remarks>
        /// <para>
        /// The input mesh and area parameters are fully validated.
        /// </para>
        /// <para>
        /// Will return null if there are zero triangles.
        /// </para>
        /// <para>
        /// All triangleswill default to <see cref="NMGen.MaxArea"/> if the
        /// <paramref name="areas"/> parameter is null.
        /// </para>
        /// <para>
        /// If walkable slope if greather than zero then the builder will apply
        /// <see cref="NMGen.ClearUnwalkableTriangles"/> to the areas.
        /// </para>
        /// </remarks>
        /// <param name="mesh">The triangle mesh to use for the build.</param>
        /// <param name="areas">The triangle areas. (Null permitted.)</param>
        /// <param name="walkableSlope">The walkable slope.
        /// (See <see cref="NMGenParams.WalkableSlope"/>)</param>
        /// <returns>A thread-safe, fully validated builder. Or null on error.</returns>
        public static InputGeometryBuilder Create(TriangleMesh mesh
                                                  , byte[] areas
                                                  , float walkableSlope)
        {
            if (!IsValid(mesh, areas))
            {
                return(null);
            }

            TriangleMesh lmesh = new TriangleMesh(mesh.vertCount, mesh.triCount);

            lmesh.triCount  = mesh.triCount;
            lmesh.vertCount = mesh.vertCount;

            System.Array.Copy(mesh.verts, 0, lmesh.verts, 0, lmesh.verts.Length);
            System.Array.Copy(mesh.tris, 0, lmesh.tris, 0, lmesh.tris.Length);

            byte[] lareas;
            if (areas == null)
            {
                lareas = NMGen.CreateDefaultAreaBuffer(mesh.triCount);
            }
            else
            {
                lareas = new byte[mesh.triCount];
                System.Array.Copy(areas, 0, lareas, 0, lareas.Length);
            }

            return(UnsafeCreate(lmesh, lareas, walkableSlope, true));
        }
        /// <summary>
        /// Adds an arbitrary group of triangles.
        /// </summary>
        /// <remarks>
        /// <para>
        /// All triangles will default to <see cref="NMGen.MaxArea"/> if the
        /// <paramref name="areas"/> parameter is null.
        /// </para>
        /// </remarks>
        /// <param name="verts">
        /// The triangle vertices. [Length: >= <paramref name="vertCount"/>]
        /// </param>
        /// <param name="vertCount">The number of vertices. [Length: >= 3]</param>
        /// <param name="tris">
        /// The triangles. [(vertAIndex, vertBIndex, vertCIndex) * triCount]
        /// [Length: >= 3 * <paramref name="triCount"/>]
        /// </param>
        /// <param name="areas">
        /// The triangle areas. (Optional) [Length: >= <paramref name="triCount"/>]
        /// </param>
        /// <param name="triCount">The number of triangles. [Limit: > 0]</param>
        /// <returns>True if the triangles were successfully added.</returns>
        public bool AddTriangles(Vector3[] verts, int vertCount
                                 , int[] tris, byte[] areas, int triCount)
        {
            if (triCount < 1 || vertCount < 3 ||
                verts == null || verts.Length < vertCount ||
                tris == null || tris.Length < triCount * 3 ||
                areas != null && areas.Length < triCount)
            {
                return(false);
            }

            if (areas == null)
            {
                areas = NMGen.CreateDefaultAreaBuffer(triCount);
            }

            int iVertOffset = mVerts.Count;

            if (vertCount == verts.Length)
            {
                mVerts.AddRange(verts);
            }
            else
            {
                mVerts.Capacity += vertCount;

                for (int p = 0; p < vertCount; p++)
                {
                    mVerts.Add(verts[p]);
                }
            }

            int length = triCount * 3;

            mTris.Capacity += length;

            for (int p = 0; p < length; p++)
            {
                mTris.Add(tris[p] + iVertOffset);
            }

            if (areas.Length == triCount)
            {
                mAreas.AddRange(areas);
            }
            else
            {
                mAreas.Capacity += triCount;

                for (int i = 0; i < triCount; i++)
                {
                    mAreas.Add(areas[i]);
                }
            }

            return(true);
        }