public static List <Mesh> MarchingCubes(this Mesh3D mesh3d, List <double> vertexValues, List <double> isoValues) { if (mesh3d?.Vertices == null || vertexValues == null || mesh3d.Vertices.Count != vertexValues.Count) { Reflection.Compute.RecordError("Number of vertexValues must match the number of vertices in the mesh."); return(new List <Mesh>()); } if (isoValues == null) { return(new List <Mesh>()); } // add empty lists List <List <Point> > vertices = new List <List <Point> >(); List <List <Face> > faces = new List <List <Face> >(); for (int i = 0; i < isoValues.Count; i++) { vertices.Add(new List <Point>()); faces.Add(new List <Face>()); } // SubMesh works on regular meshes, and since we're looking at it one cell at a time, the extra information in the mesh3d is not needed Mesh meshVersion = mesh3d.ToMesh(); // Look at every cell foreach (List <Face> cell in mesh3d.Cells()) { // Create a mesh from the cell var meshAndValues = SubMesh(meshVersion, cell, vertexValues); // Find the iso lines for the boundary of the cell List <List <Polyline> > pLines = MarchingSquares(meshAndValues.Item1, meshAndValues.Item2, isoValues).Select(x => x.Join()).ToList(); // Create faces from the polyline // Note that each vertex may be added twice here from neighboring cells for (int j = 0; j < isoValues.Count; j++) { foreach (Polyline polyline in pLines[j]) { vertices[j].AddRange(polyline.ControlPoints.Skip(1)); int nPts = vertices[j].Count; int first = polyline.ControlPoints.Count - 1; // A rough triangulation of the imagined face covering the polyline, (assumes convex polyline) for (int i = 1; i < first - 1; i++) { faces[j].Add(new Face() { A = nPts - first, B = nPts - (i + 1), C = nPts - i, }); } } } } return(vertices.Zip(faces, (v, f) => new Mesh() { Vertices = v, Faces = f, }).ToList()); }