All files / core/src/cache/classes Mesh.ts

0% Statements 0/60
0% Branches 0/12
0% Functions 0/7
0% Lines 0/58

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135                                                                                                                                                                                                                                                                             
import vtkActor from '@kitware/vtk.js/Rendering/Core/Actor';
import vtkMapper from '@kitware/vtk.js/Rendering/Core/Mapper';
import vtkPLYReader from '@kitware/vtk.js/IO/Geometry/PLYReader';
import vtkSTLReader from '@kitware/vtk.js/IO/Geometry/STLReader';
import vtkXMLPolyDataReader from '@kitware/vtk.js/IO/XML/XMLPolyDataReader';
import vtkOBJReader from '@kitware/vtk.js/IO/Misc/OBJReader';
import vtkProperty from '@kitware/vtk.js/Rendering/Core/Property';
import vtkPolyDataNormals from '@kitware/vtk.js/Filters/Core/PolyDataNormals';
 
import type { MeshData, RGB } from '../../types';
import { MeshType } from '../../enums';
 
type MeshProps = MeshData;
 
/**
 * Mesh class for storing mesh data
 * Each Mesh represents a single actor a 3D mesh.
 */
export class Mesh {
  readonly id: string;
  readonly sizeInBytes: number;
  private _color: RGB = [255, 255, 255];
  private _actors: vtkActor[] = [];
  private _format: string;
 
  /**
   * Creates an instance of Mesh.
   * @param {MeshProps} props - The properties to initialize the Mesh with.
   */
  constructor(props: MeshProps) {
    this.id = props.id;
    this._color = props.color ?? this._color;
    this._format = props.format;
 
    const textDecoder = new TextDecoder();
    const normals = vtkPolyDataNormals.newInstance();
 
    const createActorWithMapper = (mapper: vtkMapper) => {
      const actor = vtkActor.newInstance();
      actor.setMapper(mapper);
      const property = vtkProperty.newInstance();
      property.setColor(
        this._color[0] / 255,
        this._color[1] / 255,
        this._color[2] / 255
      );
      actor.setProperty(property);
      return actor;
    };
 
    if (this._format === MeshType.PLY) {
      const mapper = vtkMapper.newInstance();
      const reader = vtkPLYReader.newInstance();
      reader.parseAsArrayBuffer(props.arrayBuffer);
      mapper.setInputConnection(reader.getOutputPort());
      this._actors.push(createActorWithMapper(mapper));
    } else if (this._format === MeshType.STL) {
      const mapper = vtkMapper.newInstance();
      const reader = vtkSTLReader.newInstance();
      reader.parseAsArrayBuffer(props.arrayBuffer);
      normals.setInputConnection(reader.getOutputPort());
      mapper.setInputConnection(normals.getOutputPort());
      this._actors.push(createActorWithMapper(mapper));
    } else if (this._format === MeshType.OBJ) {
      const reader = vtkOBJReader.newInstance({
        splitMode: props.materialUrl ? 'usemtl' : null,
      });
      reader.parseAsText(textDecoder.decode(props.arrayBuffer));
      const size = reader.getNumberOfOutputPorts();
      for (let i = 0; i < size; i++) {
        const source = reader.getOutputData(i);
        const mapper = vtkMapper.newInstance();
        mapper.setInputData(source);
        this._actors.push(createActorWithMapper(mapper));
      }
    } else if (this._format === MeshType.VTP) {
      const mapper = vtkMapper.newInstance();
      const reader = vtkXMLPolyDataReader.newInstance();
      reader.parseAsArrayBuffer(props.arrayBuffer);
      mapper.setInputConnection(reader.getOutputPort());
      this._actors.push(createActorWithMapper(mapper));
    }
 
    this.sizeInBytes = this._getSizeInBytes();
  }
 
  /**
   * Calculates the size of the surface in bytes.
   * @returns {number} The size of the surface in bytes.
   * @private
   */
  private _getSizeInBytes(): number {
    let size = 0;
    for (let i = 0; i < this._actors.length; i++) {
      const actor = this._actors[i];
      const mapper = actor.getMapper();
      const pd = mapper.getInputData();
      const points = pd.getPoints();
      const polys = pd.getPolys();
      const pointsLength = points.getData().length;
      const polysLength = polys.getData().length;
      size += pointsLength * 4 + polysLength * 4;
    }
    return size;
  }
 
  /**
   * Gets the default actor of the mesh.
   * @returns {vtkActor} The points of the surface.
   */
  get defaultActor(): vtkActor {
    return this._actors[0];
  }
 
  /**
   * Gets the actors of the mesh.
   * @returns {vtkActor[]} The actors of the mesh.
   */
  get actors(): vtkActor[] {
    return this._actors;
  }
 
  /**
   * Gets the color of the mesh.
   * @returns {RGB} The color of the mesh.
   */
  get color(): RGB {
    return this._color;
  }
 
  get format(): string {
    return this._format;
  }
}