Reference Source

src/viewer/scene/CameraControl/lib/controllers/PickController.js

import {math} from "../../../math/math.js";
import {PickResult} from "../../../webgl/PickResult.js";

/**
 *
 * @private
 */
class PickController {

    constructor(cameraControl, configs) {

        this._scene = cameraControl.scene;

        this._cameraControl = cameraControl;

        this._scene.canvas.canvas.oncontextmenu = function (e) {
            e.preventDefault();
        };

        this._configs = configs;

        /**
         * Set true to schedule picking of an Entity.
         * @type {boolean}
         */
        this.schedulePickEntity = false;

        /**
         * Set true to schedule picking of a position on teh surface of an Entity.
         * @type {boolean}
         */
        this.schedulePickSurface = false;

        /**
         * The canvas position at which to do the next scheduled pick.
         * @type {Number[]}
         */
        this.pickCursorPos = math.vec2();

        /**
         * Will be true after picking to indicate that something was picked.
         * @type {boolean}
         */
        this.picked = false;

        /**
         * Will be true after picking to indicate that a position on the surface of an Entity was picked.
         * @type {boolean}
         */
        this.pickedSurface = false;

        /**
         * Will hold the PickResult after after picking.
         * @type {PickResult}
         */
        this.pickResult = null;

        this._lastPickedEntityId = null;

        this._needFireEvents = false;
    }

    /**
     * Immediately attempts a pick, if scheduled.
     */
    update() {

        if (!this._configs.pointerEnabled) {
            return;
        }

        if (!this.schedulePickEntity && !this.schedulePickSurface) {
            return;
        }

        this.picked = false;
        this.pickedSurface = false;
        this._needFireEvents = false;

        const hasHoverSurfaceSubs = this._cameraControl.hasSubs("hoverSurface");

        if (this.schedulePickSurface) {
            if (this.pickResult && this.pickResult.worldPos) {
                const pickResultCanvasPos = this.pickResult.canvasPos;
                if (pickResultCanvasPos[0] === this.pickCursorPos[0] && pickResultCanvasPos[1] === this.pickCursorPos[1]) {
                    this.picked = true;
                    this.pickedSurface = true;
                    this._needFireEvents = hasHoverSurfaceSubs;
                    this.schedulePickEntity = false;
                    this.schedulePickSurface = false;
                    return;
                }
            }
        }

        if (this.schedulePickEntity) {
            if (this.pickResult) {
                const pickResultCanvasPos = this.pickResult.canvasPos;
                if (pickResultCanvasPos[0] === this.pickCursorPos[0] && pickResultCanvasPos[1] === this.pickCursorPos[1]) {
                    this.picked = true;
                    this.pickedSurface = false;
                    this._needFireEvents = false;
                    this.schedulePickEntity = false;
                    this.schedulePickSurface = false;
                    return;
                }
            }
        }

        if (this.schedulePickSurface) {

            this.pickResult = this._scene.pick({
                pickSurface: true,
                pickSurfaceNormal: true,
                canvasPos: this.pickCursorPos
            });

            if (this.pickResult) {
                this.picked = true;
                this.pickedSurface = true;
                this._needFireEvents = true;
            }

        } else { // schedulePickEntity == true

            this.pickResult = this._scene.pick({
                canvasPos: this.pickCursorPos
            });

            if (this.pickResult) {
                this.picked = true;
                this.pickedSurface = false;
                this._needFireEvents = true;
            }
        }

        this.schedulePickEntity = false;
        this.schedulePickSurface = false;
    }

    fireEvents() {

        if (!this._needFireEvents) {
            return;
        }

        if (this.picked && this.pickResult && this.pickResult.entity) {

            const pickedEntityId = this.pickResult.entity.id;

            if (this._lastPickedEntityId !== pickedEntityId) {

                if (this._lastPickedEntityId !== undefined) {
                    this._cameraControl.fire("hoverOut", {
                        entity: this._scene.objects[this._lastPickedEntityId]
                    }, true);
                }

                this._cameraControl.fire("hoverEnter", this.pickResult, true);
                this._lastPickedEntityId = pickedEntityId;
            }

            this._cameraControl.fire("hover", this.pickResult, true);

            if (this.pickResult.worldPos) {
                this.pickedSurface = true;
                this._cameraControl.fire("hoverSurface", this.pickResult, true);
            }

        } else {

            if (this._lastPickedEntityId !== undefined) {
                this._cameraControl.fire("hoverOut", {
                    entity: this._scene.objects[this._lastPickedEntityId]
                }, true);
                this._lastPickedEntityId = undefined;
            }

            this._cameraControl.fire("hoverOff", {
                canvasPos: this.pickCursorPos
            }, true);
        }

        this.pickResult = null;

        this._needFireEvents = false;
    }

    destroy() {
        this._scene.off(this._onTick);
    }
}

export {PickController};