mcubes.ts 2.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657
  1. /**
  2. * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info.
  3. *
  4. * @author David Sehnal <david.sehnal@gmail.com>
  5. */
  6. import { Run } from 'mol-task'
  7. import { computeMarchingCubes } from 'mol-geo/util/marching-cubes/algorithm'
  8. import { Mesh } from 'mol-geo/shape/mesh'
  9. import { Tensor, Mat4, Vec3 } from 'mol-math/linear-algebra'
  10. function fillField(tensor: Tensor, f: (x: number, y: number, z: number) => number, min: number[], max: number[]): Tensor {
  11. const { space: { set, dimensions: [ii, jj, kk] }, data } = tensor;
  12. const dx = (max[0] - min[0]) / (ii - 1);
  13. const dy = (max[1] - min[1]) / (jj - 1);
  14. const dz = (max[2] - min[2]) / (kk - 1);
  15. for (let i = 0, x = min[0]; i < ii; i++, x += dx) {
  16. for (let j = 0, y = min[1]; j < jj; j++, y += dy) {
  17. for (let k = 0, z = min[2]; k < kk; k++, z += dz) {
  18. set(data, i, j, k, f(x, y, z));
  19. }
  20. }
  21. }
  22. return tensor
  23. }
  24. export default async function computeSurface(f: (x: number, y: number, z: number) => number, data?: { field: Tensor, surface: Mesh }) {
  25. let field: Tensor;
  26. if (data) field = data.field;
  27. else {
  28. const space = Tensor.Space([30, 30, 30], [0, 1, 2]);
  29. field = Tensor.create(space, space.create(Float32Array));
  30. }
  31. const min = Vec3.create(-1.1, -1.1, -1.1), max = Vec3.create(1.1, 1.1, 1.1);
  32. fillField(field, f, min, max);
  33. const surface = await Run(computeMarchingCubes({
  34. scalarField: field,
  35. isoLevel: 0,
  36. oldSurface: data ? data.surface : void 0
  37. }));
  38. const translation = Mat4.fromTranslation(Mat4.zero(), min);
  39. const grid = Vec3.zero();
  40. Vec3.fromArray(grid, field.space.dimensions as any, 0);
  41. const size = Vec3.sub(Vec3.zero(), max, min);
  42. const scale = Mat4.fromScaling(Mat4.zero(), Vec3.create(size[0] / (grid[0] - 1), size[1] / (grid[1] - 1), size[2] / (grid[2] - 1)));
  43. const transform = Mat4.mul(Mat4.zero(), translation, scale);
  44. Mesh.transformImmediate(surface, transform);
  45. Mesh.computeNormalsImmediate(surface);
  46. return { surface, field };
  47. }