Home Reference Source

viewer/sectionplane.js

import * as vec2 from "./glmatrix/vec2.js";
import * as vec3 from "./glmatrix/vec3.js";
import * as vec4 from "./glmatrix/vec4.js";
import { WSQuad } from "./wsquad.js";

const X = vec3.fromValues(1., 0., 0.);
const Y = vec3.fromValues(0., 1., 0.);
const Z = vec3.fromValues(0., 0., 1.);

const _tmp_sectionU = vec3.create();
const _tmp_sectionV = vec3.create();
const _tmp_sectionA = vec3.create();
const _tmp_sectionB = vec3.create();
const _tmp_sectionC = vec3.create();
const _tmp_sectionD = vec3.create();
const _tmp_section_dir_2d = vec4.create();

const _sectionPlaneValuesDisabled = new Float32Array([0,0,0,1]);

export class SectionPlane {

    constructor(params) {
        this.viewer = params.viewer;

        this.values = params.buffer ? params.buffer : vec4.create();
        this.values2 = vec4.create();
        this.quad = new WSQuad(this.viewer, this.viewer.gl);

        this.coordinates = null;
        this.normal = null;

        this.disable();

        // A SVG canvas overlay polygon to indicate section plane positioning
        this.Poly = null;
		this.isTempDisabled = false;
    }

    position(coordinates, normal) {
        if (coordinates) {
            this.coordinates = coordinates;
            this.normal = normal;
        } else {
            coordinates = this.coordinates;
            normal = this.normal;
        }

        let ref = null;
        if (Math.abs(vec3.dot(normal, Z)) < 0.9) {
            ref = Z;
        } else {
            ref = X;
        }

        let cameraEye = this.viewer.camera.eye;
        vec3.subtract(_tmp_sectionA, cameraEye, coordinates);
        let cameraDistance = vec3.len(_tmp_sectionA);

        vec3.cross(_tmp_sectionU, normal, ref);
        vec3.cross(_tmp_sectionV, normal, _tmp_sectionU);
        vec3.scale(_tmp_sectionU, _tmp_sectionU, cameraDistance / 50.);
        vec3.scale(_tmp_sectionV, _tmp_sectionV, cameraDistance / 50.);

        // ---
        
        vec3.add(_tmp_sectionA, _tmp_sectionU, coordinates);
        vec3.add(_tmp_sectionB, _tmp_sectionU, coordinates);

        vec3.negate(_tmp_sectionU, _tmp_sectionU);

        vec3.add(_tmp_sectionC, _tmp_sectionU, coordinates);
        vec3.add(_tmp_sectionD, _tmp_sectionU, coordinates);

        // ---

        vec3.add(_tmp_sectionA, _tmp_sectionV, _tmp_sectionA);
        vec3.add(_tmp_sectionC, _tmp_sectionV, _tmp_sectionC);

        vec3.negate(_tmp_sectionV, _tmp_sectionV);

        vec3.add(_tmp_sectionB, _tmp_sectionV, _tmp_sectionB);
        vec3.add(_tmp_sectionD, _tmp_sectionV, _tmp_sectionD);

        // ---

        let ps = [_tmp_sectionA, _tmp_sectionB, _tmp_sectionD, _tmp_sectionC, _tmp_sectionA];
        if (this.Poly) {
            this.Poly.points = ps;
        } else {
            this.Poly = this.viewer.overlay.createWorldSpacePolyline(ps);
            this.Poly.beforeUpdate = () => {
                this.position();
            }
        }

        // temporarily set values to render quad
        this.values.set(normal.subarray(0,3));
        this.values[3] = vec3.dot(coordinates, normal);
        this.quad.position(this.viewer.modelBounds, this.values);
        this.values.set(_sectionPlaneValuesDisabled);
    }

    enable(canvasPos, coordinates, normal, depth) {
        this.values.set(normal.subarray(0,3));
        this.initialSectionPlaneD = this.values[3] = vec3.dot(coordinates, normal);
        this.values2.set(this.values);
        this.isDisabled = false;
        this.depth = depth;
        let cp = [canvasPos[0] / this.viewer.width, - canvasPos[1] / this.viewer.height];
        this.DownAt = cp;
    }

    tempDisable() {
        if (!this.isTempDisabled) {
            this.values2.set(this.values);
            this.values.set(_sectionPlaneValuesDisabled);
            this.isTempDisabled = true;
        }
    }

    tempRestore() {
        if (this.isTempDisabled) {
            this.values.set(this.values2);
            this.isTempDisabled = false;
        }
    }

    drawQuad() {
        // @todo is it actually necessary to disable? it seems to function without
        this.tempDisable();
        this.quad.draw();
        this.tempRestore();
    }

    disable() {
        this.values.set(_sectionPlaneValuesDisabled);
        this.values2.set(_sectionPlaneValuesDisabled);
        this.isDisabled = true;
    }

    move(canvasPos) {
        _tmp_section_dir_2d.set(this.values2);
        _tmp_section_dir_2d[3] = 0.;
        vec4.transformMat4(_tmp_section_dir_2d, _tmp_section_dir_2d, this.viewer.camera.viewProjMatrix);
        let cp = [canvasPos[0] / this.viewer.width, - canvasPos[1] / this.viewer.height];        
        vec2.subtract(_tmp_section_dir_2d.subarray(2), cp, this.DownAt);
        _tmp_section_dir_2d[1] /= this.viewer.width / this.viewer.height;
        let d = vec2.dot(_tmp_section_dir_2d, _tmp_section_dir_2d.subarray(2)) * this.depth;
        this.values2[3] = this.initialSectionPlaneD + d;

        this.quad.position(this.viewer.modelBounds, this.values2);
    }

    destroy() {
        if (this.Poly) {
            this.Poly.destroy();
            this.Poly = null;
        }
    }

}