public float [] Generate(Mesh inputMesh, int radius = 5, bool useKring = true)
        {
            var unaliasedGenerator = new UnaliasedMeshGenerator();
            var unaliasedMesh      = unaliasedGenerator.GenerateUnaliasedMesh(inputMesh);

            var verticesFlatArray       = unaliasedMesh.Vertices.SelectMany(c => c.ToArray()).ToArray();
            var unaliasedVerticesCount  = unaliasedMesh.Vertices.Length;
            var unaliasedTrianglesCount = unaliasedMesh.Triangles.Length / 3;

            var outDirection1 = new float[3 * unaliasedVerticesCount];
            var outDirection2 = new float[3 * unaliasedVerticesCount];
            var outValues1    = new float[unaliasedVerticesCount];
            var outValues2    = new float[unaliasedVerticesCount];

            var sw = new MyStopWatch();

            sw.StartSegment("pc");
            PrincipalCurvatureDll.EnableLogging();
            int callStatus = PrincipalCurvatureDll.compute_principal_curvature(verticesFlatArray, unaliasedVerticesCount, unaliasedMesh.Triangles, unaliasedTrianglesCount, outDirection1, outDirection2,
                                                                               outValues1, outValues2, radius, useKring);

            sw.StartSegment("pc2");
            Preconditions.Assert(callStatus == 0, "Calling compute_principal_curvature failed, as returned status " + callStatus);
            //RemapCurvatureData(outDirection1, outDirection2, outValues1, outValues2);

            var inputVerticesCount = inputMesh.vertices.Length;
            var outArray           = new float[inputVerticesCount * 8];

            for (int i = 0; i < unaliasedVerticesCount; i++)
            {
                foreach (var inputVerticleIndex in unaliasedMesh.VerticlesToOriginalVerticles[unaliasedMesh.Vertices[i]])
                {
                    var outArrayIdx = inputVerticleIndex * 8;
                    var inArrayIdx  = i * 3;
                    outArray[outArrayIdx + 0] = outDirection1[inArrayIdx + 0];
                    outArray[outArrayIdx + 1] = outDirection1[inArrayIdx + 1];
                    outArray[outArrayIdx + 2] = outDirection1[inArrayIdx + 2];

                    outArray[outArrayIdx + 3] = outValues1[i];

                    outArray[outArrayIdx + 4] = outDirection2[inArrayIdx + 0];
                    outArray[outArrayIdx + 5] = outDirection2[inArrayIdx + 1];
                    outArray[outArrayIdx + 6] = outDirection2[inArrayIdx + 2];

                    outArray[outArrayIdx + 7] = outValues2[i];
                }
            }
            Debug.Log("A22: " + sw.CollectResults());
            return(outArray);
        }
        public float [] Generate(Mesh inputMesh, int radius = 5, bool useKring = true)
        {
            var unaliasedGenerator = new UnaliasedMeshGenerator();
            var unaliasedMesh      = unaliasedGenerator.GenerateUnaliasedMesh(inputMesh);

            var verticesFlatArray       = unaliasedMesh.Vertices.SelectMany(c => VectorUtils.ToArray((Vector3)c)).ToArray();
            var unaliasedVerticesCount  = unaliasedMesh.Vertices.Length;
            var unaliasedTrianglesCount = unaliasedMesh.Triangles.Length / 3;

            var floatsPerVertex   = (3 + 1 + 3 + 1 + 4);
            var unaliasedOutArray = new float[unaliasedVerticesCount * floatsPerVertex];

            var sw = new MyStopWatch();

            sw.StartSegment("trimesh2_compute_principal_curvature - computing");
            PrincipalCurvatureDll.EnableLogging();
            int callStatus = PrincipalCurvatureDll.trimesh2_compute_principal_curvature(verticesFlatArray, unaliasedVerticesCount, unaliasedMesh.Triangles,
                                                                                        unaliasedTrianglesCount, unaliasedOutArray);

            sw.StartSegment("trimesh2_compute_principal_curvature - aliasing");
            Preconditions.Assert(callStatus == 0, "Calling trimesh2_compute_principal_curvature failed, as returned status " + callStatus);
            //RemapCurvatureData(outDirection1, outDirection2, outValues1, outValues2);

            var inputVerticesCount = inputMesh.vertices.Length;
            var outArray           = new float[inputVerticesCount * floatsPerVertex];

            for (int i = 0; i < unaliasedVerticesCount; i++)
            {
                foreach (var inputVerticleIndex in unaliasedMesh.VerticlesToOriginalVerticles[unaliasedMesh.Vertices[i]])
                {
                    for (int j = 0; j < floatsPerVertex; j++)
                    {
                        outArray[inputVerticleIndex * floatsPerVertex + j] = unaliasedOutArray[i * floatsPerVertex + j];
                    }
                }
            }
            Debug.Log("A22: " + sw.CollectResults());
            return(outArray);
        }
        public List <PointWithNormal> ProvideSamples(int samplesCount, float minimumDistance, Mesh mesh)
        {
            var unaliasedGenerator = new UnaliasedMeshGenerator();
            var unaliasedMesh      = unaliasedGenerator.GenerateUnaliasedMesh(mesh);

            var verticesFlatArray       = unaliasedMesh.Vertices.SelectMany(c => VectorUtils.ToArray((Vector3)c)).ToArray();
            var unaliasedVerticesCount  = unaliasedMesh.Vertices.Length;
            var unaliasedTrianglesCount = unaliasedMesh.Triangles.Length / 3;

            var flatOutSamplesArray    = new float[samplesCount * 3];
            var outOwningTriangleArray = new int[samplesCount];

            PrincipalCurvatureDll.EnableLogging();
            int callStatus = 0;
            var randomPointsMaxTriesCount = 100;

            for (int i = 0; i < randomPointsMaxTriesCount; i++)
            {
                callStatus = PrincipalCurvatureDll.random_points_on_mesh(verticesFlatArray, unaliasedVerticesCount, unaliasedMesh.Triangles,
                                                                         unaliasedTrianglesCount, samplesCount, flatOutSamplesArray, outOwningTriangleArray);
                if (callStatus != 0)
                {
                    Debug.Log($" PrincipalCurvatureDll.random_points_on_mesh call failed with status {callStatus}, retrying");
                }
                else
                {
                    break;
                }
            }
            Preconditions.Assert(callStatus == 0, "Calling random_points_on_mesh failed, as returned status " + callStatus);

            var pointWithNormals = new List <PointWithNormal>();

            for (int i = 0; i < samplesCount; i++)
            {
                var point         = new Vector3(flatOutSamplesArray[i * 3 + 0], flatOutSamplesArray[i * 3 + 1], flatOutSamplesArray[i * 3 + 2]);
                var triangleIndex = outOwningTriangleArray[i];

                var v1 = unaliasedMesh.Vertices[unaliasedMesh.Triangles[triangleIndex * 3 + 0]];
                var v2 = unaliasedMesh.Vertices[unaliasedMesh.Triangles[triangleIndex * 3 + 1]];
                var v3 = unaliasedMesh.Vertices[unaliasedMesh.Triangles[triangleIndex * 3 + 2]];

                var normal = Vector3.Cross(v2 - v1, v3 - v1).normalized;
                pointWithNormals.Add(new PointWithNormal()
                {
                    Normal = normal, Position = point
                });
            }

            for (int i = 0; i < pointWithNormals.Count; i++)
            {
                var current       = pointWithNormals[i];
                var itemsToRemove = pointWithNormals.Select((c, j) => new { c, j })
                                    .Where(c => c.j != i && Vector3.Distance(c.c.Position, current.Position) < minimumDistance).Select(c => c.j).ToList();

                for (int j = itemsToRemove.Count - 1; j >= 0; j--)
                {
                    pointWithNormals.RemoveAt(itemsToRemove[j]);
                }
            }

            return(pointWithNormals);
        }