public static bool RandomizeMesh(g3.DMesh3 mesh, out g3.DMesh3 outputMesh, double amount, double moveTries)
        {
            System.Collections.Generic.SortedDictionary <int, MeshNode> faces = new System.Collections.Generic.SortedDictionary <int, MeshNode>();

            int index = 0;

            foreach (var meshFaceIndex in mesh.TriangleIndices())
            {
                var frame = mesh.GetTriFrame(meshFaceIndex);

                g3.Index3i neighbors    = mesh.GetTriNeighbourTris(meshFaceIndex);
                g3.Index3i vertex_index = mesh.GetTriangle(meshFaceIndex);

                faces.Add(meshFaceIndex, new MeshNode(index++, meshFaceIndex, frame, neighbors, vertex_index));
            }

            foreach (var f in faces)
            {
                f.Value.neighbors.Clear();
                f.Value.neighbors.Capacity = 3;
                for (int i = 0; i < 3; ++i)
                {
                    int fn = f.Value.neighbors_index[i];
                    if (fn >= 0)
                    {
                        f.Value.neighbors.Add(faces[fn]);
                    }
                }

                if (f.Value.neighbors.Count < 3)
                {
                    f.Value.locked = true;

                    foreach (var n in f.Value.neighbors)
                    {
                        n.locked = true;
                    }
                }
            }

            DMesh3 projectMeshCopy = new DMesh3(mesh);

            outputMesh = new DMesh3(mesh);

            if (faces.Count == 0)
            {
                return(false);
            }


            DMeshAABBTree3 treeProject = new DMeshAABBTree3(projectMeshCopy);

            treeProject.Build();

            Random r = new Random();

            bool result = false;


            //for (int i = 0; i < moveTries; i++)
            //{
            double faceArea = 0;

            foreach (var f in faces)
            {
                faceArea += f.Value.TriangleArea(outputMesh);
            }

            faceArea /= faces.Count;

            foreach (var f in faces)
            {
                result |= f.Value.Randomize(outputMesh, treeProject, r, amount, moveTries, faceArea);
            }

            double newFaceArea = 0;

            foreach (var f in faces)
            {
                newFaceArea += f.Value.TriangleArea(outputMesh);
            }

            newFaceArea /= faces.Count;

            return(result);
        }
        //public static void VoronoiMesh(List<g3.PolyLine3d> mesh, out List<g3.Line3d> listLines, out List<g3.PolyLine3d> listPolylines)
        //{
        //    System.Collections.Generic.SortedDictionary<int, MeshNode> faces = new System.Collections.Generic.SortedDictionary<int, MeshNode>();

        //    int index = 0;
        //    foreach (var meshFaceIndex in mesh.TriangleIndices())
        //    {
        //        var frame = mesh.GetTriFrame(meshFaceIndex);

        //        g3.Index3i neighbors = mesh.GetTriNeighbourTris(meshFaceIndex);
        //        g3.Index3i vertex_index = mesh.GetTriangle(meshFaceIndex);

        //        faces.Add(meshFaceIndex, new MeshNode(index++, meshFaceIndex, frame, neighbors, vertex_index));
        //    }


        //    foreach (var f in faces)
        //    {
        //        f.Value.neighbors.Clear();
        //        f.Value.neighbors.Capacity = 3;
        //        for (int i = 0; i < 3; ++i)
        //        {
        //            int fn = f.Value.neighbors_index[i];
        //            if (fn >= 0)
        //                f.Value.neighbors.Add(faces[fn]);
        //        }

        //        if (f.Value.neighbors.Count < 3)
        //        {
        //            f.Value.locked = true;

        //            foreach (var n in f.Value.neighbors)
        //                n.locked = true;
        //        }
        //    }

        //    outputMesh = new g3.DMesh3(g3.MeshComponents.None);
        //    listLines = new List<g3.Line3d>();
        //    listPolylines = new List<g3.PolyLine3d>();
        //    foreach (var f in faces)
        //    {
        //        outputMesh.AppendVertex(f.Value.frame.Origin);
        //    }

        //    HashSet<int> processedPoints = new HashSet<int>();

        //    foreach (var f in faces)
        //    {
        //        for (int i = 0; i < 3; i++)
        //        {
        //            List<int> outputLine = new List<int>();

        //            if (processedPoints.Contains(f.Value.vertex_index[i]))
        //                continue;

        //            int checkVertex = f.Value.vertex_index[i];

        //            MeshNode currentFaces = f.Value;
        //            MeshNode prevFace = null;

        //            bool fullLoop = false;

        //            while (true)
        //            {
        //                for (int j = 0; j < currentFaces.neighbors.Count; j++)
        //                {

        //                    var neighbor = currentFaces.neighbors[j];
        //                    if (neighbor.UsesVertex(checkVertex))
        //                    {

        //                        if (neighbor == prevFace)
        //                            continue;

        //                        if (neighbor == f.Value)
        //                        {
        //                            fullLoop = true;
        //                            break; // Found full loop
        //                        }

        //                        outputLine.Add(neighbor.index);

        //                        prevFace = currentFaces;
        //                        currentFaces = neighbor;
        //                        j = -1;
        //                    }
        //                }

        //                break;
        //            }

        //            if (fullLoop)
        //            {
        //                processedPoints.Add(checkVertex);

        //                var polyline = new g3.PolyLine3d();

        //                if (outputLine.Count > 2)
        //                {
        //                    g3.Vector3d centerPoint = f.Value.frame.Origin;

        //                    foreach (var p in outputLine)
        //                        centerPoint += outputMesh.GetVertex(p);

        //                    centerPoint /= (outputLine.Count + 1);

        //                    int center = outputMesh.AppendVertex(centerPoint);

        //                    var pS = outputMesh.GetVertex(f.Value.index);
        //                    var p0 = outputMesh.GetVertex(outputLine[0]);
        //                    var pE = outputMesh.GetVertex(outputLine[outputLine.Count - 1]);

        //                    var normal = mesh.GetTriNormal(f.Value.meshIndex);

        //                    polyline.AppendVertex(pS);
        //                    polyline.AppendVertex(p0);

        //                    listLines.Add(new g3.Line3d(pS, p0 - pS));

        //                    var n = MathUtil.Normal(centerPoint, pS, p0);

        //                    bool reverseTri = n.Dot(normal) < 0;

        //                    if (!reverseTri)
        //                        outputMesh.AppendTriangle(center, f.Value.index, outputLine[0]);
        //                    else
        //                        outputMesh.AppendTriangle(center, outputLine[0], f.Value.index);

        //                    for (int j = 0; j < outputLine.Count - 1; j++)
        //                    {
        //                        var p1 = outputMesh.GetVertex(outputLine[j]);
        //                        var p2 = outputMesh.GetVertex(outputLine[j + 1]);

        //                        listLines.Add(new g3.Line3d(p1, p2 - p1));
        //                        polyline.AppendVertex(p2);

        //                        if (!reverseTri)
        //                            outputMesh.AppendTriangle(center, outputLine[j], outputLine[j + 1]);
        //                        else
        //                            outputMesh.AppendTriangle(center, outputLine[j + 1], outputLine[j]);
        //                    }

        //                    polyline.AppendVertex(pS);
        //                    listLines.Add(new g3.Line3d(pE, pS - pE));

        //                    listPolylines.Add(polyline);

        //                    if (!reverseTri)
        //                        outputMesh.AppendTriangle(center, outputLine[outputLine.Count - 1], f.Value.index);
        //                    else
        //                        outputMesh.AppendTriangle(center, f.Value.index, outputLine[outputLine.Count - 1]);
        //                }
        //            }
        //        }

        //    }
        //}

        public static void VoronoiMesh(g3.DMesh3 mesh, out g3.DMesh3 outputMesh, out List <g3.Line3d> listLines, out List <g3.PolyLine3d> listPolylines)
        {
            System.Collections.Generic.SortedDictionary <int, MeshNode> faces = new System.Collections.Generic.SortedDictionary <int, MeshNode>();

            int index = 0;

            foreach (var meshFaceIndex in mesh.TriangleIndices())
            {
                var frame = mesh.GetTriFrame(meshFaceIndex);

                g3.Index3i neighbors    = mesh.GetTriNeighbourTris(meshFaceIndex);
                g3.Index3i vertex_index = mesh.GetTriangle(meshFaceIndex);

                faces.Add(meshFaceIndex, new MeshNode(index++, meshFaceIndex, frame, neighbors, vertex_index));
            }


            foreach (var f in faces)
            {
                f.Value.neighbors.Clear();
                f.Value.neighbors.Capacity = 3;
                for (int i = 0; i < 3; ++i)
                {
                    int fn = f.Value.neighbors_index[i];
                    if (fn >= 0)
                    {
                        f.Value.neighbors.Add(faces[fn]);
                    }
                }

                if (f.Value.neighbors.Count < 3)
                {
                    f.Value.locked = true;

                    foreach (var n in f.Value.neighbors)
                    {
                        n.locked = true;
                    }
                }
            }

            outputMesh    = new g3.DMesh3(g3.MeshComponents.None);
            listLines     = new List <g3.Line3d>();
            listPolylines = new List <g3.PolyLine3d>();
            foreach (var f in faces)
            {
                outputMesh.AppendVertex(f.Value.frame.Origin);
            }

            HashSet <int> processedPoints = new HashSet <int>();

            foreach (var f in faces)
            {
                for (int i = 0; i < 3; i++)
                {
                    List <int> outputLine = new List <int>();

                    if (processedPoints.Contains(f.Value.vertex_index[i]))
                    {
                        continue;
                    }

                    int checkVertex = f.Value.vertex_index[i];

                    MeshNode currentFaces = f.Value;
                    MeshNode prevFace     = null;

                    bool fullLoop = false;

                    while (true)
                    {
                        for (int j = 0; j < currentFaces.neighbors.Count; j++)
                        {
                            var neighbor = currentFaces.neighbors[j];
                            if (neighbor.UsesVertex(checkVertex))
                            {
                                if (neighbor == prevFace)
                                {
                                    continue;
                                }

                                if (neighbor == f.Value)
                                {
                                    fullLoop = true;
                                    break; // Found full loop
                                }

                                outputLine.Add(neighbor.index);

                                prevFace     = currentFaces;
                                currentFaces = neighbor;
                                j            = -1;
                            }
                        }

                        break;
                    }

                    if (fullLoop)
                    {
                        processedPoints.Add(checkVertex);

                        var polyline = new g3.PolyLine3d();

                        if (outputLine.Count > 2)
                        {
                            g3.Vector3d centerPoint = f.Value.frame.Origin;

                            foreach (var p in outputLine)
                            {
                                centerPoint += outputMesh.GetVertex(p);
                            }

                            centerPoint /= (outputLine.Count + 1);

                            int center = outputMesh.AppendVertex(centerPoint);

                            var pS = outputMesh.GetVertex(f.Value.index);
                            var p0 = outputMesh.GetVertex(outputLine[0]);
                            var pE = outputMesh.GetVertex(outputLine[outputLine.Count - 1]);

                            var normal = mesh.GetTriNormal(f.Value.meshIndex);

                            polyline.AppendVertex(pS);
                            polyline.AppendVertex(p0);

                            listLines.Add(new g3.Line3d(pS, p0 - pS));

                            var n = MathUtil.Normal(centerPoint, pS, p0);

                            bool reverseTri = n.Dot(normal) < 0;

                            if (!reverseTri)
                            {
                                outputMesh.AppendTriangle(center, f.Value.index, outputLine[0]);
                            }
                            else
                            {
                                outputMesh.AppendTriangle(center, outputLine[0], f.Value.index);
                            }

                            for (int j = 0; j < outputLine.Count - 1; j++)
                            {
                                var p1 = outputMesh.GetVertex(outputLine[j]);
                                var p2 = outputMesh.GetVertex(outputLine[j + 1]);

                                listLines.Add(new g3.Line3d(p1, p2 - p1));
                                polyline.AppendVertex(p2);

                                if (!reverseTri)
                                {
                                    outputMesh.AppendTriangle(center, outputLine[j], outputLine[j + 1]);
                                }
                                else
                                {
                                    outputMesh.AppendTriangle(center, outputLine[j + 1], outputLine[j]);
                                }
                            }

                            polyline.AppendVertex(pS);
                            listLines.Add(new g3.Line3d(pE, pS - pE));

                            listPolylines.Add(polyline);

                            if (!reverseTri)
                            {
                                outputMesh.AppendTriangle(center, outputLine[outputLine.Count - 1], f.Value.index);
                            }
                            else
                            {
                                outputMesh.AppendTriangle(center, f.Value.index, outputLine[outputLine.Count - 1]);
                            }
                        }
                    }
                }
            }
        }