Reference Source

src/viewer/scene/math/MeshVolume.js

import {math} from "./math.js";
import {isTriangleMeshSolid} from "./isTriangleMeshSolid.js";

const v1 = math.vec3();
const v2 = math.vec3();
const v3 = math.vec3();

/**
 * Calculates the volume of triangle meshes.
 */
export class MeshVolume {
    constructor() {
        this.vertices = [];
        this.indices = [];
        this.reset();
    }

    /**
     * Resets, ready to add vertices and indices for a new mesh.
     */
    reset() {
        this.lenVertices = 0;
        this.lenIndices = 0;
        this.primitive = null;
    }

    setPrimitive(primitive) {
        this.primitive = primitive;
    }

    /**
     * Adds a vertex.
     * @param vertex
     */
    addVertex(vertex) {
        this.vertices[this.lenVertices++] = vertex[0];
        this.vertices[this.lenVertices++] = vertex[1];
        this.vertices[this.lenVertices++] = vertex[2];
    }

    /**
     * Adds an index.
     * @param index
     */
    addIndex(index) {
        this.indices[this.lenIndices++] = index;
    }

    /**
     * Gets the volume of the mesh.
     *
     * The mesh must be a closed solid.
     *
     * @returns {number} The volume of the mesh, or -1 if the mesh is not solid, in which case volume cannot be determined.
     */
    get volume() {

        const vertices = this.vertices;
        const indices = this.indices;

        if (this.primitive !== "solid" && this.primitive !== "surface" && this.primitive !== "triangles") {
            return -1;
        }

        if (this.primitive !== "solid" && !isTriangleMeshSolid(indices, vertices)) {
            return -1;
        }

        let volume = 0;

        for (let i = 0; i < this.lenIndices; i += 3) {

            const index1 = indices[i] * 3;
            const index2 = indices[i + 1] * 3;
            const index3 = indices[i + 2] * 3;

            v1[0] = vertices[index1];
            v1[1] = vertices[index1 + 1];
            v1[2] = vertices[index1 + 2];

            v2[0] = vertices[index2];
            v2[1] = vertices[index2 + 1];
            v2[2] = vertices[index2 + 2];

            v3[0] = vertices[index3];
            v3[1] = vertices[index3 + 1];
            v3[2] = vertices[index3 + 2];

            math.cross3Vec3(v1, v2, v1);

            volume += math.dotVec3(v1, v3);
        }

        return volume / 6;
    }
}

/**
 * Singleton instance of {@link MeshVolume}.
 * @type {MeshVolume}
 */
export const meshVolume = new MeshVolume();