/// <summary>
        ///
        /// </summary>
        /// <param name="args"></param>
        public static void Start()
        {
            var mesh  = HeMesh3d.Factory.CreateFromOBJ(Paths.Resources + _fileIn);
            var verts = mesh.Vertices;

            var    texCoords = new Vec2d[verts.Count];
            double scale     = 0.5;
            double offset    = scale * Math.PI * 0.25;

            // create texture coordinates from implicit function
            for (int i = 0; i < verts.Count; i++)
            {
                var p = verts[i].Position * scale;
                var u = ImplicitSurfaces.Gyroid(p.X, p.Y, p.Z);
                var v = ImplicitSurfaces.Gyroid(p.X + offset, p.Y + offset, p.Z + offset);
                texCoords[i] = new Vec2d(u, v);
            }

            // compute vertex normals & write to file
            mesh.UpdateVertexNormals();
            MeshIO.WriteToObj(mesh, Paths.Resources + _fileOut, v => texCoords[v]);

            Console.WriteLine("File written successfully. Press return to exit.");
            Console.ReadLine();
        }
        /// <summary>
        ///
        /// </summary>
        public static void Start()
        {
            // import halfedge mesh
            var mesh = HeMesh3d.Factory.CreateFromOBJ(Paths.Resources + _fileIn);

            // create particles
            var particles = mesh.Vertices.Select(v => new Particle(v.Position)).ToArray();

            // create constraints
            var constraints = mesh.Faces.Where(f => !f.IsDegree3)
                              .Select(f => new PlanarNgon(f.Vertices.Select(v => v.Index)))
                              .ToArray();

            // create solver
            var solver = new ConstraintSolver();

            // wait for keypress to start the solver
            Console.WriteLine("Press return to start the solver.");
            Console.ReadLine();

            // step the solver until converged
            while (!solver.IsConverged)
            {
                solver.Step(particles, constraints, true);
                Console.WriteLine($"    step {solver.StepCount}");
            }
            Console.WriteLine("\nSolver converged! Press return to exit.");

            // update mesh vertices
            mesh.Vertices.Action(v => v.Position = particles[v].Position); // mesh elements (vertices, halfedges, faces) are implicitly converted to their index

            // compute vertex normals & write to file
            mesh.UpdateVertexNormals(true);
            MeshIO.WriteToObj(mesh, Paths.Resources + _fileOut);
            Console.ReadLine();
        }