Source: package/component/positioned_component.js

import { pause, checkPropTypes, UUIDRegex } from '../../lib.js';
import { Matrix4, Object3D, Vector2, Vector3, Quaternion, Group, Mesh, Vector4, Math, Euler } from '../../../node_modules/three/build/three.module.js';
import { Reporter } from '../../reporter/reporter.js';
import { Project } from '../../project.js';
import { BuildableComponent } from './buildable_component.js';
import { Export } from '../../export/export.js';

/**
 * Situates components; provides them with a position and quaternion
 */

class PositionedComponent extends BuildableComponent {

    /**
     * @param {Reporter} reporter
     * @param {Object} settings
     * @param {UUID} [settings.id]
     * @param {Vector3} settings.position
     * @param {Quaternion} settings.quaternion
     * @param {Boolean} [settings.assignable = false]
     * @param {BuildableComponent} settings.component
     */

    constructor(reporter, settings) {

        settings.assignable = settings.assignable === true ? true : false;

        super(
            reporter,
            settings,
        );

        checkPropTypes(
            settings,
            {
                component: [
                    {
                        test: BuildableComponent,
                        msg: 'must be buildable'
                    },
                    {
                        test: val => !(val instanceof PositionedComponent),
                        msg: 'Do not nest positioned components'
                    },
                ],
                quaternion: Quaternion,
                position: Vector3
            },
            {}
        );

        // fucking typescript
        if (!Object.getOwnPropertyDescriptor(this, 'component')) {
            /** @type {BuildableComponent} */
            this.component = settings.component;
        }
        if (!Object.getOwnPropertyDescriptor(this, 'assignable')) { //['get']) {
            /** @type {Boolean} */
            Object.defineProperty(
                this,
                'assignable',
                {
                    get : () => settings.component.assignable
                }
            );
        }
    }


    /** @type {ExportLevel} */

    static _exportLevel = 'inline';


    /** @type {Boolean} */

    get materializable() {
        return this.component.settings.materialVariantGroup !== undefined;
    }


    async _build(part, quality, dependencies) {

        switch (part) {
            case 'UI':

                this._setContent(
                    'UI',
                    quality,
                    this._settings.component.content.UI[quality]
                );
                break;

            case 'main':

                const depContent = this._settings.component.content.main[quality];

                const clonableContent = depContent instanceof Object3D ? depContent : Object.values(depContent).find(depObjVal => depObjVal instanceof Object3D);

                const clonedObject3D = clonableContent.clone();

                clonedObject3D.castShadow = true;
                clonedObject3D.receiveShadow = true;

                clonedObject3D.layers.set( Project.layerMap.visibleActors );

                // LOCAL - OBJECT - WORLD SPACE TRANSFORMS
                // transforms need to be done in world space!

                //-------------------- JSON TRANSFROMS TRANSLATION--------------------------

                // Apply specified translation from json
                clonedObject3D.translateX(this._settings.position.x);
                clonedObject3D.translateY(this._settings.position.y);
                clonedObject3D.translateZ(this._settings.position.z);


                //-------------------- GLTF BASIS TRANSFROMS --------------------------

                // Apply the quaternion from the imported file axes
                if (depContent.transformMatrix instanceof Matrix4) {

                    //clonedObject3D.applyMatrix4( depContent.transformMatrix); //transformMatrix toepassen voor de juiste import in et assenstelesel
                    clonedObject3D.setRotationFromMatrix(depContent.transformMatrix); //transformMatrix toepassen voor de juiste import in et assenstelesel

                }

                //------------------- JSON TRANSFORM ROTATION ------------
                //console.log( this._settings.quaternion )

                clonedObject3D.quaternion.multiply(this._settings.quaternion)



                clonedObject3D.updateMatrixWorld();


                // console.log( this.label, Object.keys( this ) );


                // THREE.js clone function does JSON.stringify(JSON.parse)
                // and since this engine relies heavily on the clone function
                // storing a direct reference to an object is not possible

                // clonedObject3D.userData.origin = this;   // <-- does not work, unfortunately

                // so we can use Object3D.findByName in the scene
                clonedObject3D.name = this.id;

                // let's deprecate this:
                Object.defineProperty(
                    clonedObject3D.userData,
                    'origin',
                    {
                        get: () => {
                            console.log( 'DEPRECATED! Use userData.PB.origin' );
                            return this.id;
                        }
                    }
                );
                
                // in favor of this:
                clonedObject3D.userData.PB = {
                    origin: this.id,
                    type: this.constructor.name
                };

                this._setContent(
                    'main',
                    quality,
                    clonedObject3D
                );
                break;

            default:

                this._setContent(part, quality, null);
                
                break;
        }

        return this;
    }
}

export { PositionedComponent };