function create_level_surface(f, domain, opts = {}) {
let {
Nx = 30,
Ny = 30,
Nz = 30,
color = "#40bfbf",
transparency = 0,
show_surface_mesh = false
} = opts;
let resolution = [Nx, Ny, Nz];
let b = domain.map((b, i) => [b[0], (b[1] - b[0]) / (resolution[i] - 1)]);
let gridValues = ndarrayProxy(resolution, (i, j, k) =>
f(b[0][0] + i * b[0][1], b[1][0] + j * b[1][1], b[2][0] + k * b[2][1])
);
let mesh = surfaceNets(gridValues);
for (var i = 0; i < mesh.positions.length; i++) {
const p = mesh.positions[i];
p[0] = b[0][0] + b[0][1] * p[0];
p[1] = b[1][0] + b[1][1] * p[1];
p[2] = b[2][0] + b[2][1] * p[2];
}
let container = d3.create("transform");
if (opts.id) {
container.attr("id", opts.id);
}
if (opts.class) {
container.attr("class", opts.class);
}
mesh.cells.forEach((pt) => pt.push(pt[0]));
let face_index_string = mesh.cells.join(" -1 ").toString();
let coord_string = mesh.positions.toString();
let shape = container.append("shape");
let appearance = shape.append("appearance");
if (opts.sortKey || opts.sortKey === 0) {
appearance.attr("sortKey", opts.sortKey);
}
let material = appearance.append("material");
material.attr("diffuseColor", color);
if (opts.transparency) {
material.attr("transparency", opts.transparency);
}
let indexedFaceSet = shape
.append("indexedFaceset")
.attr("solid", false)
.attr("coordIndex", face_index_string)
.attr("creaseAngle", 3.14);
indexedFaceSet.append("coordinate").attr("point", coord_string);
if (show_surface_mesh) {
let surface_mesh = container.append("shape");
surface_mesh
.append("appearance")
.append("material")
.attr("transparency", 0.4);
surface_mesh
.append("IndexedLineSet")
.attr("coordIndex", face_index_string)
.append("Coordinate")
.attr("point", coord_string);
}
let xs = mesh.positions.map((pt) => pt[0]);
let xmin = d3.min(xs);
let xmax = d3.max(xs);
let ys = mesh.positions.map((pt) => pt[1]);
let ymin = d3.min(ys);
let ymax = d3.max(ys);
let zs = mesh.positions.map((pt) => pt[2]);
let zmin = d3.min(zs);
let zmax = d3.max(zs);
let node = container.node();
node.extent = { xmin, xmax, ymin, ymax, zmin, zmax };
return node;
}