static void Test(VertexModifier vertexModifier, MeshRebuilder rebuilder, CostMetricMeasurer costMeasurer, string testName, int iterations)
        {
            Random random = new Random(5);
            double sum = 0;
            double fastest = double.MaxValue;
            double slowest = 0;
            for (int iterationIndex = 0; iterationIndex < iterations; ++iterationIndex)
            {
                vertexModifier(random);

                var start = Stopwatch.GetTimestamp();
                rebuilder(iterationIndex);
                var end = Stopwatch.GetTimestamp();

                var time = (end - start) / (double)Stopwatch.Frequency;

                if (time < fastest) fastest = time;
                if (time > slowest) slowest = time;

                sum += time;
            }
            Console.WriteLine($"{testName}:");
            Console.WriteLine($"Average: {sum / iterations}");
            Console.WriteLine($"Fastest: {fastest}");
            Console.WriteLine($"Slowest: {slowest}");
            if (costMeasurer != null)
                Console.WriteLine($"Cost Metric: {costMeasurer()}");
        }
        static void Build2(int gridSize, out VertexModifier vertexModifier, out Dictionary<string, MeshRebuilder> rebuilders, out CostMetricMeasurer costMeasurer, out MeshDisposer disposer)
        {
            List<Vector3> vertices = new List<Vector3>();

            for (int y = 0; y < gridSize; ++y)
                for (int x = 0; x < gridSize; ++x)
                    vertices.Add(new Vector3(2 * x, 0, 2 * y));

            List<int> triangles = new List<int>();

            for (int y = 0; y < gridSize - 1; ++y)
                for (int x = 0; x < gridSize - 1; ++x)
                {
                    triangles.Add(gridSize * (y) + (x));
                    triangles.Add(gridSize * (y) + (x + 1));
                    triangles.Add(gridSize * (y + 1) + (x + 1));

                    triangles.Add(gridSize * (y) + (x));
                    triangles.Add(gridSize * (y + 1) + (x + 1));
                    triangles.Add(gridSize * (y + 1) + (x));
                }

            var physicsMesh = new Mesh(vertices.ToArray(), triangles.ToArray());

            vertexModifier = (Random random) =>
            {
                for (int vertexIndex = 0; vertexIndex < physicsMesh.Vertices.Length; ++vertexIndex)
                    physicsMesh.Vertices[vertexIndex].Y = (float)random.NextDouble() * 2;
            };

            rebuilders = new Dictionary<string, MeshRebuilder>();
            //Note incremental first, sweep second. Starts the refine off with a better tree to begin with so it doesn't to do an unrealistic amount of optimization to begin with.
            rebuilders.Add("v2 Reconstruct Incremental", (i) => physicsMesh.RebuildIncremental());
            rebuilders.Add("v2 Reconstruct Sweep", (i) => physicsMesh.RebuildSweep());
            rebuilders.Add("v2 Refit And Refine", (i) => physicsMesh.RefitWithIncrementalRefine(i));
            rebuilders.Add("v2 Refit", (i) => physicsMesh.Refit());

            disposer = () => { physicsMesh.Tree.Dispose(); };

            costMeasurer = () => { return physicsMesh.Tree.MeasureCostMetric(); };
        }