getBoundary.js 5.86 KB
import { Vector3, Matrix4 } from 'three';

import { _worker_getMaxMinZValue } from './worker/boundary.worker';
import MainThreadController from './worker/MainThreadController';
import safeStringify from 'fast-safe-stringify';

export const getBoundarybox = (geometry, matrix = new Matrix4()) => {
    let max_x = -1000;
    let max_y = -1000;
    let max_z = -1000;
    let min_x = 1000;
    let min_y = 1000;
    let min_z = 1000;
    let position = geometry.getAttribute('position');
    if (!position) {
        return null;
    }
    let i = 0;
    while (i < position.count) {
        let vertex = { x: position.getX(i), y: position.getY(i), z: position.getZ(i) };
        let vector3 = new Vector3(vertex.x, vertex.y, vertex.z);
        vector3.applyMatrix4(matrix);
        if (vector3.x > max_x) {
            max_x = vector3.x;
        }
        if (vector3.y > max_y) {
            max_y = vector3.y;
        }
        if (vector3.z > max_z) {
            max_z = vector3.z;
        }
        if (vector3.x < min_x) {
            min_x = vector3.x;
        }
        if (vector3.y < min_y) {
            min_y = vector3.y;
        }
        if (vector3.z < min_z) {
            min_z = vector3.z;
        }
        ++i;
    }
    let box = {
        max: new Vector3(max_x, max_y, max_z),
        min: new Vector3(min_x, min_y, min_z),
        center: new Vector3((min_x + max_x) * 0.5, (min_y + max_y) * 0.5, (min_z + max_z) * 0.5)
    };
    return box;
};

export const getGeometryCenter = (geometry, matrix = new Matrix4()) => {
    let position = geometry.getAttribute('position');
    if (!position) {
        return null;
    }
    let x = 0,
        y = 0,
        z = 0;
    for (let i = 0; i < position.count; i++) {
        let vertex = { x: position.getX(i), y: position.getY(i), z: position.getZ(i) };
        let vector3 = new Vector3(vertex.x, vertex.y, vertex.z);
        vector3.applyMatrix4(matrix);
        x += vector3.x;
        y += vector3.y;
        z += vector3.z;
    }
    return new Vector3(x / position.count, y / position.count, z / position.count);
};

export const getBoundaryboxes = (meshs) => {
    let max_x = -10000;
    let max_y = -10000;
    let max_z = -10000;
    let min_x = 10000;
    let min_y = 10000;
    let min_z = 10000;
    for (let el = 0; el < meshs.length; el++) {
        let geometry = meshs[el].geometry;
        let matrix = meshs[el].matrix;
        let box = meshs[el].box ? meshs[el].box : getBoundarybox(geometry, matrix);
        if (!meshs[el].box) meshs[el].box = box;

        if (!box.max) {
            return {
                max: new Vector3(),
                min: new Vector3()
            };
        }
        max_x = Math.max(box.max.x, max_x);
        max_y = Math.max(box.max.y, max_y);
        max_z = Math.max(box.max.z, max_z);

        min_x = Math.min(box.min.x, min_x);
        min_y = Math.min(box.min.y, min_y);
        min_z = Math.min(box.min.z, min_z);
    }
    let box = {
        max: new Vector3(max_x, max_y, max_z),
        min: new Vector3(min_x, min_y, min_z),
        center: new Vector3((min_x + max_x) * 0.5, (min_y + max_y) * 0.5, (min_z + max_z) * 0.5)
    };
    return box;
};

export const getPointsBoundary = (points) => {
    let max_x = -10000;
    let max_y = -10000;
    let max_z = -10000;
    let min_x = 10000;
    let min_y = 10000;
    let min_z = 10000;
    for (let el = 0; el < points.length; el++) {
        let point = points[el];
        if (point.x > max_x) {
            max_x = point.x;
        }
        if (point.y > max_y) {
            max_y = point.y;
        }
        if (point.z > max_z) {
            max_z = point.z;
        }
        if (point.x < min_x) {
            min_x = point.x;
        }
        if (point.y < min_y) {
            min_y = point.y;
        }
        if (point.z < min_z) {
            min_z = point.z;
        }
    }
    let box = {
        max: new Vector3(max_x, max_y, max_z),
        min: new Vector3(min_x, min_y, min_z),
        center: new Vector3((min_x + max_x) * 0.5, (min_y + max_y) * 0.5, (min_z + max_z) * 0.5)
    };
    return box;
};

export const getPointsCenter = (points) => {
    const center = new Vector3();
    points.forEach((el) => {
        center.add(el);
    });
    center.multiplyScalar(1 / points.length);
    return center;
};

export const getMaxMinZValue = (geometry, matrix) => {
    const position = geometry.getAttribute('position');
    const e = matrix.elements;
    let min = Infinity;
    let max = -Infinity;
    let x, y, z, w, newZ;
    let i = position.count - 1;
    while (i >= 0) {
        x = position.getX(i);
        y = position.getY(i);
        z = position.getZ(i);
        w = 1 / (e[3] * x + e[7] * y + e[11] * z + e[15]);
        newZ = (e[2] * x + e[6] * y + e[10] * z + e[14]) * w;
        min = Math.min(newZ, min);
        max = Math.max(newZ, max);
        --i;
    }
    return {
        max,
        min
    };
};

export const getMaxMinZValues = (objects) => {
    let minimum = Infinity;
    let maximum = -Infinity;
    objects.forEach((el) => {
        const { max, min } = getMaxMinZValue(el.geometry, el.matrix);
        minimum = Math.min(min, minimum);
        maximum = Math.max(max, maximum);
    });
    return {
        max: maximum,
        min: minimum
    };
};

export const workerGetMaxMinZValue = (positions, matrix, callback) => {
    if (window.Worker) {
        const blob = new Blob([_worker_getMaxMinZValue], { type: 'application/javascript' });
        const mainThreadController = new MainThreadController({
            workerUrl: window.URL.createObjectURL(blob),
            workerName: 'getMaxMinZValue'
        });
        const matrixs = JSON.parse(safeStringify.stableStringify(matrix));
        mainThreadController.postMessage({ positions, matrixs }).then((response) => {
            if (response) {
                const { max, min } = response;
                if (callback) callback(max, min);
            }
        });
    }
};