API Docs for: 2.0.0
Show:

File: src/viewer/labelling/position.js

/**
 A **Position** is a spatial location within a {{#crossLink "Viewer"}}{{/crossLink}}.

 ## Overview

 A Position provides its coordinates in each of BIMSurfer's five coordinate systems:

 <ul>
 <li>{{#crossLink "Position/pos:property"}}{{/crossLink}} - 3D coordinates within the Position's local Model coordinate system.</li>
 <li>{{#crossLink "Position/worldPos:property"}}{{/crossLink}} - 3D coordinates within the Viewer's current World coordinate
 system, after transformation by the {{#crossLink "Position/matrix:property"}}Position's modelling matrix{{/crossLink}}.</li>
 <li>{{#crossLink "Position/viewPos:property"}}{{/crossLink}} - 3D coordinates within the Viewer's current View
 coordinate system, after transformation by the {{#crossLink "Viewer/viewMatrix:property"}}Viewer's view matrix{{/crossLink}}.</li>
 <li>{{#crossLink "Position/projPos:property"}}{{/crossLink}} - 3D coordinates within the Viewer's current Projection
 coordinate system, after transformation by the {{#crossLink "Viewer/projMatrix:property"}}Viewer's projection matrix{{/crossLink}}.</li>
 <li>{{#crossLink "Position/canvasPos:property"}}{{/crossLink}} - 2D coordinates within the Viewer's current Canvas
 coordinate system.</li>
 </ul>

 ## Example

 ````Javascript
 // Create a Viewer
 var viewer = new BIMSURFER.Viewer({ element: "myDiv" });

 // Create a Camera
 var camera = new BIMSURFER.Camera(viewer, {
     eye: [20, 20, -20]
 });

 // Create a CameraControl to interact with the Camera
 var cameraControl = new BIMSURFER.CameraControl(viewer, {
    camera: camera
 });

 // Create a Position
 new BIMSURFER.Position(viewer, {
    pos: [0,0,0],
    matrix: BIMSURFER.math.translationMat4v([4, 0,0])
 });

 ````

 @class Position
 @module BIMSURFER
 @module labelling
 @constructor
 @param [viewer] {Viewer} Parent {{#crossLink "Viewer"}}{{/crossLink}}.
 @param [cfg] {*} Configs
 @param [cfg.id] {String} Optional ID, unique among all components in the parent viewer, generated automatically when omitted.
 @param [cfg.meta] {String:Object} Optional map of user-defined metadata to attach to this Position.
 @param [cfg.pos] {Array of Number} Position's 3D location.
 @param [cfg.matrix=[1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1]] {Array of Number} Transform matrix - a one-dimensional, sixteen element array of elements, an identity matrix by default.
 @extends Component
 */
(function () {

    "use strict";

    BIMSURFER.Position = BIMSURFER.Component.extend({

        /**
         JavaScript class name for this Component.

         @property className
         @type String
         @final
         */
        className: "BIMSURFER.Position",

        _init: function (cfg) {

            this._viewMatrix = this.viewer.viewMatrix;
            this._projMatrix = this.viewer.projMatrix;

            this._pos = [0, 0, 0];
            this._worldPos = [0, 0, 0];
            this._viewPos = [0, 0, 0];
            this._projPos = [0, 0, 0];
            this._canvasPos = [0, 0, 0];

            this._updatedirty = true;
            this._worldPosDirty = true;
            this._viewPosDirty = true;
            this._projPosDirty = true;
            this._canvasPosDirty = true;

            var self = this;

            this._onViewMatrix = this.viewer.on("viewMatrix",
                function (matrix) {

                    self._viewMatrix = matrix;

                    self._updatedirty = true;
                    self._viewPosDirty = true;
                    self._projPosDirty = true;
                    self._canvasPosDirty = true;
                });

            this._onProjMatrix = this.viewer.on("projMatrix",
                function (matrix) {

                    self._projMatrix = matrix;

                    self._updatedirty = true;
                    self._projPosDirty = true;
                    self._canvasPosDirty = true;
                });

            this._onTick = this.viewer.on("tick",
                function () {
                    if (self._updatedirty) {
                        self.fire("updated");
                        self._updatedirty = false;
                    }
                });

            this.pos = cfg.pos;

            this.matrix = cfg.matrix;
        },

        _props: {

            /**
             * The Position's 3D coordinates within its local Model coordinate system, ie. before transformation by
             * the Position's {{#crossLink "Position/matrix:property"}}matrix{{/crossLink}}.
             *
             * @property pos
             * @default [0,0,0]
             * @type {Array of Number}
             */
            pos: {

                set: function (value) {

                    value = value || [0, 0, 0];

                    if (value[0] !== this._pos[0] ||
                        value[1] !== this._pos[1] ||
                        value[2] !== this._pos[2]) {

                        this._pos[0] = value[0];
                        this._pos[1] = value[1];
                        this._pos[2] = value[2];

                        this._updatedirty = true;
                        this._worldPosDirty = true;
                        this._viewPosDirty = true;
                        this._projPosDirty = true;
                        this._canvasPosDirty = true;
                    }
                },

                get: function () {
                    return this._pos;
                }
            },

            /**
             * This Positions's 4x4 modelling transformation matrix.
             *
             * @property matrix
             * @default [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1]
             * @type {Array of Number}
             */
            matrix: {

                set: function (value) {

                    value = value || [ 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1 ];

                    this._updatedirty = true;
                    this._worldPosDirty = true;
                    this._viewPosDirty = true;
                    this._projPosDirty = true;
                    this._canvasPosDirty = true;

                    this._matrix = value;
                },

                get: function () {
                    return this._matrix;
                }
            },

            /**
             * This Position's 3D coordinates within the World coordinate system, ie. after transformation by
             * the Position's {{#crossLink "Position/matrix:property"}}matrix{{/crossLink}} and before
             * transformation by Viewer's {{#crossLink "Viewer/viewMatrix:property"}}viewing matrix{{/crossLink}}.
             *
             * @property worldPos
             * @final
             * @default [0,0,0]
             * @type {Array of Number}
             */
            worldPos: {

                get: function () {

                    if (this._worldPosDirty) {

                        if (this._matrix) {

                            BIMSURFER.math.transformPoint3(this._matrix, this._pos, this._worldPos);

                        } else {

                            this._worldPos[0] = this._pos[0];
                            this._worldPos[1] = this._pos[1];
                            this._worldPos[2] = this._pos[2];
                        }

                        this._worldPosDirty = false;
                    }

                    return this._worldPos;
                }
            },

            /**
             * This Position's 3D coordinates within the View coordinate system, ie. after transformation by
             * the Viewer's {{#crossLink "Viewer/viewMatrix:property"}}view matrix{{/crossLink}} and before
             * transformation by the Viewer's {{#crossLink "Viewer/projMatrix:property"}}projection matrix{{/crossLink}}.
             *
             * @property viewPos
             * @final
             * @type {Array of Number}
             */
            viewPos: {

                get: function () {

                    if (this._viewPosDirty) {

                        BIMSURFER.math.transformPoint3(this._viewMatrix, this.worldPos, this._viewPos);

                        this._viewPos[3] = 1; // Need homogeneous 'w' for perspective division

                        this._viewPosDirty = false;
                    }

                    return this._viewPos;
                }
            },

            /**
             * This Position's 3D homogeneous coordinates within the Projection coordinate system, ie. after transformation by
             * the Viewer's {{#crossLink "Viewer/projMatrix:property"}}projection matrix{{/crossLink}}.
             *
             * @property projPos
             * @final
             * @type {Array of Number}
             */
            projPos: {

                get: function () {

                    if (this._projPosDirty) {

                        BIMSURFER.math.transformPoint3(this._projMatrix, this.viewPos, this._projPos);

                        this._projPosDirty = false;
                    }

                    return this._projPos;
                }
            },

            /**
             * This Position's 2D coordinates within the Canvas coordinate system.
             *
             * @property canvasPos
             * @final
             * @type {Array of Number}
             */
            canvasPos: {

                get: function () {

                    if (this._canvasPosDirty) {

                        var projPos = this.projPos;

                        var x = projPos[0];
                        var y = projPos[1];
                        var w = projPos[3];

                        var canvas = this.viewer.canvas.canvas;

                        this._canvasPos[0] = Math.round((1 + x / w) * canvas.width / 2);
                        this._canvasPos[1] = Math.round((1 - y / w) * canvas.height / 2);

                        this._canvasPosDirty = false;
                    }

                    return this._canvasPos;
                }
            }
        },

        _destroy: function () {

            this.viewer.off(this._onViewMatrix);

            this.viewer.off(this._onProjMatrix);

            this.viewer.off(this._onTick);
        }
    });
})();