Source

adapter/IModelViewer.js

//
// $Id: IModelViewer.js 9255 2025-11-08 12:45:26Z jochen.hanff $


const selectionChanged = new CustomEvent("selection-changed");
const visibilityChanged = new CustomEvent("visibility-changed");

import { Context } from "../infohub/Context.js"


/**
 *
 *  @category Model Viewer
 * 
 */
export class ProjectContext {

    project = null
    scope   = null
    connectedby = null

    constructor() {}

    setScopeProject( scope , project , connectedby ) {
        this.project = project
        this.scope = scope
        this.connectedby = connectedby
    }

}


/**
 *  @typedef {object} ApiResponse
 *  @property {number} status - HTTP-like status code
 *  @property {string} [message] - Optional descriptive message
 *  @property {*} data - The actual payload of the response
 */

/**
 *
 *  @category Model Viewer
 *
 *  @classdesc IModelViewer
 *
 *      Common Interface for Model Viewers such as DESITE, COLNEO pro, Web Viewer etc.
 *
 *      Throws event `selection-changed` when selection of objects in 3d view is changed
 *      Throws event `visibility-changed` when visibility of objects in 3d view is changed
 *
*/
export class IModelViewer extends EventTarget {

    apiName = null
    viewerName = null
    viewerVersion = null

    // infohub project context ( scope , project )
    /* ProjectContext */ _infohub_project_ctx = null

    constructor( t = 'unknow' , n = 'unknown' , v = '0.0.0' ) {
        super()
        this.apiName        = t;
        this.viewerName     = n;
        this.viewerVersion  = v;
        this._infohub_project_ctx = new ProjectContext()
    }

    // ======== user, infohub context (scope,project) ========

    /**
     * 
     * Get 
     * user,token
     * from ModelViewer
     * 
     * returns {
     *      'status' :
     *      'data'  : {
     *          'user'  : " ... "
     *          'token' : " ... "
     *      }
     * }
     * 
     * @param {*} cb 
     * @param {*} user           
     * 
     */
    loginUser( cb , user = null ) {
        return Promise.reject("No model viewer instantiated");
    }

    logoutUser( cb ) {
        return Promise.reject("No model viewer instantiated");
    }

    /**
     *
     * Restore project context (scope,project) from model viewer (from current project)
     * and store it in infohub context ctx.     
     *
     * @param {Context} ctx
     * @param {*} cb Call back
     * @returns {Promise<ApiResponse>} Returns object with status and ProjectContext data
     */
    async restoreProjectContext( ctx , cb ) {
        console.error(`ERROR in ${this.apiName}.getProjectInfo(): No model viewer instantiated.`)
        return Promise.reject("No model viewer instantiated");
    }

    saveProjectContext( cb ) {
        console.error(`ERROR in ${this.apiName}.getProjectInfo(): No model viewer instantiated.`)
        return Promise.reject("No model viewer instantiated");
    }

    getProjectContext() {
        return this._infohub_project_ctx
    }

    /**
   * Get name and version of the current ModelViewer.
   * @returns {object} JSON object containing name and version.
   * @since 10.2025
   */
    getInfo() {
        return {
            name    : this.viewerName,
            type    : this.apiName,
            version : this.viewerVersion
        }
    }

    /**!
     * Dump info to console
     */
    dump() {
        console.log( JSON.stringify(this.getInfo(),null,2))
    }

    /**
     * 
     * Connect signals selection changed and visibility changed to given functions
     * 
     * returns {
     *      'status' : ...
     * }
     * 
     * @param {function} on_sc on selection changed
     * @param {function} on_vc on visibility changed
     * @param {*} cb      
     * 
     */
    connectModelViewer(on_sc, on_vc, cb) {
        
        this.addEventListener("selection-changed", on_sc)
        this.addEventListener("visibility-changed", on_vc)

        return cb({
            'status': 200
        })

    }

    /**
     *
     */
    onSelectionChanged() {
        this.dispatchEvent(selectionChanged)
    }

    /**
     *
     */
    onVisibilityChanged() {
        this.dispatchEvent(visibilityChanged)
    }

    // ======== Project Methods ========

    /**
     * Get project metadata
     * @returns {ApiResponse<object>} //RM
     * @since 10.2025
     */
    getProjectInfo(projectId) {
        console.error(`ERROR in ${this.apiName}.getProjectInfo(): No model viewer instantiated.`)
        return Promise.reject("No model viewer instantiated");
    }

    /**
     * Get project directory
     * @returns {ApiResponse<string>} file path
     */
    getProjectDirectory(projectId) {
        console.error(`ERROR in ${this.apiName}.getProjectDirectory(): No model viewer instantiated.`)
        return Promise.reject("No model viewer instantiated");
    }

    /**
     * Save current project, show SaveFileDialog if project was newly created and no file path is available.
     * @returns {ApiResponse<boolean>} True if project was saved successfully.
     */
    saveProject() {
        console.error(`ERROR in ${this.apiName}.saveProject(): No model viewer instantiated.`)
        return Promise.reject("No model viewer instantiated");
    }


    // ======== Model Methods ========

    /**
     * Get model IDs for given domains.
     * @param {string[]} domain - Domain (e.g. 'all') or combination as array, e.g. ['geo', 'act'].
     * @returns {ApiResponse<string[]>} Array of model IDs.
     * @since 10.2025
     */
    getModelIds(domain) {
        console.error(`ERROR in ${this.apiName}.getModelIds(): No model viewer instantiated.`)
        return Promise.reject("No model viewer instantiated");
    }

    /**
     * Get metadata for given model.
     * @param {string} modelId - Model ID.
     * @returns {ApiResponse<object>}
     * @since 10.2025
     */
    getModelMetadata(modelId) {
        console.error(`ERROR in ${this.apiName}.getModelMetadata(): No model viewer instantiated.`)
        return Promise.reject("No model viewer instantiated");
    }

    /**
     * Create model. Synchronizes with Infohub.
     * @param {string} name - Model name.
     * @param {string} domain - Domain (e.g. 'geo')
     * @param {object} settings - Model settings.
     * @returns {ApiResponse<string>} ID of newly created model.
     */
    createModel(name, domain, settings) {
        console.error(`ERROR in ${this.apiName}.createModel(): No model viewer instantiated.`)
        return Promise.reject("No model viewer instantiated");
    }

    /**
     * Add model to coordination model. Synchronizes with Infohub.
     * @param {string} modelId - Model ID.
     * @returns {ApiResponse<boolean>} True if successfully added
     */
    importModel(filename) {
        console.error(`ERROR in ${this.apiName}.addModel(): No model viewer instantiated.`)
        return Promise.reject("No model viewer instantiated");
    }

    /**
     * remove model from project. Synchronizes with Infohub.
     * @param {string} modelId - Model ID.
     * @returns {ApiResponse<boolean>} True if model was successfully removed.
     */
    removeModel(modelId) {
        console.error(`ERROR in ${this.apiName}.removeModel(): No model viewer instantiated.`)
        return Promise.reject("No model viewer instantiated");
    }

    // ======== Object Methods ========

    /**
     * Get object by ID. Synchronizes data with Infohub.
     * @param {string} objId - ID of object.
     * @returns {ApiResponse<cnObject>} returns object in GOM format
     */
    getObject( objId , keys ) {
        return this.getObject( [ objId ] , keys )
    }

    /**
     * 
     * @param {*} objIdList 
     * @param {*} opt      
     */
    getObjects( objIdList , opt ) {
        console.error(`ERROR in ${this.apiName}.getObject(): No model viewer instantiated.`)
        return Promise.reject("No model viewer instantiated");
    }

    /**
     * Create a new object. Synchronizes data with Infohub.
     * @param {string} parentId - ID of parent object
     * @param {object} data - Data for the new object in JSON notation
     * @example {
                    info: {
                        object_type : "geo_container",
                        object_name : "MyObject"
                    },
                    properties: {
                        ...
                    },
                    geometry: {
                        ...
                    }
                }
     * @returns {ApiResponse<string>} ID of newly created object.
     */
    createObject(parentId, data) {
        console.error(`ERROR in ${this.apiName}.createObject(): No model viewer instantiated.`)
        return Promise.reject("No model viewer instantiated");
    }

    /**
     * Delete objects by ID. Synchronizes data with Infohub.
     * @param {string[]} objIds - IDs of objects to delete.
     * @returns {ApiResponse<number>} Number of objects deleted.
     */
    deleteObjects(objIds) {
        console.error(`ERROR in ${this.apiName}.deleteObjects(): No model viewer instantiated.`)
        return Promise.reject("No model viewer instantiated");
    }

    /**
     * Get all object IDs for given domains as list.
     * @param {string[]} domain Domain (e.g. 'all') or combination as array, e.g. ['geo', 'act'].
     * @returns {ApiResponse<string[]>} Array of object IDs.
     */
    getObjectIds(domains) {
        console.error(`ERROR in ${this.apiName}.getObjectIds(): No model viewer instantiated.`)
        return Promise.reject("No model viewer instantiated");
    }

    /**
     * Filter objects by property values.
     * @param {string[]} objIds - Object IDs of objects to filter.
     * @param {any[]} filterExpression - Filter criteria.
     * @example [ "$ifcEntity##xs:string" , "==" , "IfcWall" ]
     * @example [ "$ifcEntity##xs:string" , "in" , ["IfcWall", "IfcWallStandardCase"]] , "and" , "$cnVolume##xs:double", ">=" , 2.5 ]]
     * @example [ "$ifcEntity##xs:string" , "match" , "/^IfcWall/g"]]
     * @returns {ApiResponse<string[]>} Filtered object IDs.
     */
    filterObjectsByProperties( objIds, filterExpression) {
        console.error(`ERROR in ${this.apiName}.filterObjectsByProperties(): No model viewer instantiated.`)
        return Promise.reject("No model viewer instantiated");
    }

    /**
     * Filter objects by status.
     * @param {string[]} objIds - Object IDs of objects to filter.
     * @param {string} statusCode - one of [ 'selected', 'visible'].
     * @param {boolean} statusFlag - true: status, false: inverted status.
     * @returns {ApiResponse<string[]>} Filtered object IDs.
     */
    filterObjectsByStatus(objIds, statusCode, statusFlag) {
        console.error(`ERROR in ${this.apiName}.filterObjectsByStatus(): No model viewer instantiated.`)
        return Promise.reject("No model viewer instantiated");
    }

    // ======== Object Status Methods ========

    /**
     * Get IDs of currently visible objects in given domain/domains.
     * @param {string[]} domain - Domain (e.g. 'all') or combination as array, e.g. ['geo', 'act'].
     * @returns {ApiResponse<string[]>} returns IDs of currently visible objects in given domain/domains
     * @since 10.2025
     */
    getVisibleObjectIds(domain) {
        console.error(`ERROR in ${this.apiName}.getVisibleObjectIds(): No model viewer instantiated.`)
        return Promise.reject("No model viewer instantiated");
    }

    /**
     * Set visibility of objects.
     * @param {string[]} objIds - Object IDs.
     * @param {boolean} flagOnOff - true: visible, false: hidden
     * @param {boolean} exclusively - If the 'exclusivly' flag is set to true, the domains affected are determined by the specified objects. The remaining objects in these domains are set to the inverse status.
     * @returns {ApiResponse<number>} Number of objects whose status changed.
     * @since 10.2025
     */
    setVisible(objIds, flagOnOff, exclusively) {
        console.error(`ERROR in ${this.apiName}.setVisible(): No model viewer instantiated.`)
        return Promise.reject("No model viewer instantiated");
    }

    /**
     * Toggle visibility of given objects.
     * @param {string[]} objIds - Object IDs to toggle.
     * @returns {ApiResponse<void>}
     */
    toggleVisibility(objIds) {
        console.error(`ERROR in ${this.apiName}.toggleVisibility(): No model viewer instantiated.`)
        return Promise.reject("No model viewer instantiated");
    }

    /**
     * Check if object is visible.
     * @param {string} objId - Object ID.
     * @returns {ApiResponse<boolean>} True if object is visible.
     */
    isVisible(objId) {
        console.error(`ERROR in ${this.apiName}.isVisible(): No model viewer instantiated.`)
        return Promise.reject("No model viewer instantiated");
    }

    /**
     * Get IDs of currently selected objects.
     * @param {string[]} domain - Domain (e.g. 'all') or combination as array, e.g. ['geo', 'act'].
     * @returns {ApiResponse<string[]>} returns IDs of currently selected objects
     * @since 10.2025
     */
    getSelectedObjectIds(domain) {
        console.error(`ERROR in ${this.apiName}.getSelectedObjectIds(): No model viewer instantiated.`)
        return Promise.reject("No model viewer instantiated");
    }

    /**
     * Set selection of objects.
     * @param {string[]} objIds - Object IDs.
     * @param {boolean} flagOnOff - Selection flag.
     * @param {boolean} exclusively - If true, clear all other selections.
     * @returns {ApiResponse<number>} Number of objects whose selection changed.
     * @since 10.2025
     */
    setSelected(objIds, flagOnOff, exclusively) {
        console.error(`ERROR in ${this.apiName}.setSelected(): No model viewer instantiated.`)
        return Promise.reject("No model viewer instantiated");
    }

    /**
     * Toggle selection status of given objects.
     * @param {string[]} objIds - Object IDs to toggle.
     * @returns {ApiResponse<void>}
     */
    toggleSelection(objIds) {
        console.error(`ERROR in ${this.apiName}.toggleSelection(): No model viewer instantiated.`)
        return Promise.reject("No model viewer instantiated");
    }

    /**
     * Check if object is selected.
     * @param {string} objId - Object ID.
     * @returns {ApiResponse<boolean>} True if object is selected.
     */
    isSelected(objId) {
        console.error(`ERROR in ${this.apiName}.isSelected(): No model viewer instantiated.`)
        return Promise.reject("No model viewer instantiated");
    }

    // ======== Hierarchy Methods ========

    /**
     * Get parent ID of object.
     * @param {string} objId - Object ID.
     * @returns {ApiResponse<string>} - ID of closest parent
     * @since 10.2025
     */
    getParentId(objId) {
        console.error(`ERROR in ${this.apiName}.getParentId(): No model viewer instantiated.`)
        return Promise.reject("No model viewer instantiated");
    }

    /**
     * Get root node of object trees for a given domain.
     * @param {string} domain - Domain (e.g. 'geo')
     * @returns {ApiResponse<string>} returns ID of root node of object trees for a given domain
     * @since 10.2025
     */
    getRootNodeId(domain) {
        console.error(`ERROR in ${this.apiName}.getRootNodeId(): No model viewer instantiated.`)
        return Promise.reject("No model viewer instantiated");
    }

    /**
     * Get root nodes of smartsets for given domain.
     * @param {string} domain - Domain (e.g. 'geo')
     * @returns {ApiResponse<string>}
     * @since 10.2025
     */
    getRootNodeIdOfSets(domain) {
        console.error(`ERROR in ${this.apiName}.getRootNodeIdOfSets(): No model viewer instantiated.`)
        return Promise.reject("No model viewer instantiated");
    }

    /**
     * Get children of object up to depth.
     * @param {string} objId - Object ID.
     * @param {number} depth - [optional] Recursion depth, default = 0 (maximum depth)
     * @returns {ApiResponse<string[]>} - IDs if contained objects upto given depth
     * @since 10.2025
     */
    getChildIds(objId, depth) {
        console.error(`ERROR in ${this.apiName}.getChildIds(): No model viewer instantiated.`)
        return Promise.reject("No model viewer instantiated");
    }

    // ======== Property Methods ========

    /**
     * Get property value for object.
     * @param {string} objId - Object ID.
     * @param {string} ptKeyStr - Access key of property type in the format name##datatype.
     * @returns {ApiResponse<any>} -alue of property, depending on the datatype
     */
    getPropertyValue(objId, ptKeyStr) {
        console.error(`ERROR in ${this.apiName}.getPropertyValue(): No model viewer instantiated.`)
        return Promise.reject("No model viewer instantiated");
    }

    /**
     * Get property values for multiple objects.
     * @param {string[]} objIds - Object IDs.
     * @param {string} ptKeyStr - Access key of property type in the format name##datatype.
     * @returns {ApiResponse<object[]>} Map with object IDs as keys.
     * @example data: {
                    "id1" : {
                        "value": 1.234,
                        "comment": ""
                    },
                    ...
                }
     */
    getPropertyValues(objIds, ptKeyStr) {
        console.error(`ERROR in ${this.apiName}.getPropertyValues(): No model viewer instantiated.`)
        return Promise.reject("No model viewer instantiated");
    }

    /**
     * Get unique property values for type.
     * @param {string} ptKeyStr - Access key of property type in the format name##datatype.
     * @param {object} options - Options for filtering.
     * @example * // Example options object:
                * const options = {
                *   objects: ['obj_1', 'obj_2'],
                *   precision: 0.0001,
                *   case_sensitive: true,
                *   interval_size: 2.0,
                *   interval_offset: 1.0,
                *   date_grouping: 'week',
                *   max_values: 0
                * };
     * @returns {ApiResponse<string[]>} returns list of unique property values
     * @since 10.2025
     */
    getPropertyTypeValues(ptKeyStr, options) {
        console.error(`ERROR in ${this.apiName}.getPropertyTypeValues(): No model viewer instantiated.`)
        return Promise.reject("No model viewer instantiated");
    }

    /**
     * Get all properties of object.
     * @param {string} objId - Object ID.
     * @param {boolean} inclPropsFromTypes - Include props from types.
     * @param {object} filter - Filter criteria.
     * @example * // Example filter object:
                * const filter = {
                *  name:       "MyPset:MyNumber*",
                *  datatype :  ["xs:double", "xs:float"]
                * };
     * @returns {ApiResponse<object>}
     * @example data: {
                    "MyPset:MyNumber##xs:double": "11",
                    "MyPset:MyNumberNew##xs:float": 42,
                }
     */
    getProperties(objId, inclPropsFromTypes, filter) {
        console.error(`ERROR in ${this.apiName}.getProperties(): No model viewer instantiated.`)
        return Promise.reject("No model viewer instantiated");
    }

    /**
     * Get property type metadata.
     * @param {string} ptKeyStr - Access key of property type in the format name##datatype.
     * @returns {ApiResponse<object|null>}
     * @example data: {
                    name: "cnName",
                    displayName: "cn:Name",
                    datatype: "xs:string",
                    readonly: false,
                    ...
                }
     */
    getPropertyTypeInfo(ptKeyStr) {
        console.error(`ERROR in ${this.apiName}.getPropertyTypeInfo(): No model viewer instantiated.`)
        return Promise.reject("No model viewer instantiated");
    }

    /**
     * Get property types used by object.
     * @param {string} objId - Object ID.
     * @param {object} filter - Filter criteria.
     * @example * // Example filter object:
                * const filter = {
                *  name:       "MyPset:MyNumber*",
                *  datatype :  ["xs:double", "xs:float"]
                *  readOnly: true
                * };
     * @returns {ApiResponse<object[]>}
     * @example data: [
                    {
                        name: "MyPset:MyNumber",
                        displayName: "MyPset:MyNumber",
                        datatype: "xs:double",
                        readonly: true,
                        ...
                    }
                ]
     *
     */
    getPropertyTypesByObject(objId, filter) {
        console.error(`ERROR in ${this.apiName}.getPropertyTypesByObject(): No model viewer instantiated.`)
        return Promise.reject("No model viewer instantiated");
    }

    /**
     * Get a list of all available property types matching filter.
     * @param {object} filter - Filter criteria.
     * @example * // Example filter object:
                * const filter = {
                *  name:       "MyPset:MyNumber*",
                *  datatype :  ["xs:double", "xs:float"]
                *  readOnly: true
                * };
     * @returns {ApiResponse<string[]>}
     */
    getPropertyTypes(filter) {
        console.error(`ERROR in ${this.apiName}.getPropertyTypes(): No model viewer instantiated.`)
        return Promise.reject("No model viewer instantiated");
    }

    /**
     * Set single property value. Synchronizes with Infohub.
     * @param {string} objId - Object ID.
     * @param {string} ptKeyStr - Access key of property type in the format name##datatype.
     * @param {string} value - New value.
     * @returns {ApiResponse<boolean>}
     */
    setPropertyValue(objId, ptKeyStr, value) {
        console.error(`ERROR in ${this.apiName}.setPropertyValue(): No model viewer instantiated.`)
        return Promise.reject("No model viewer instantiated");
    }

    /**
     * Set multiple property values. Synchronizes with Infohub.
     * @param {string[]} objIds - Object IDs.
     * @param {object} propertyMap - Key/value pairs, key format name##datatype
     *  @example * // Example propertyMap object:
                * const propertyMap = {
                *   "myType##xs:string": "ABC",
                *   "myNumber##xs:double": 1.234,
                *   "myBoolean##xs:boolean": true
                * };
     * @returns {ApiResponse<boolean>}
     */
    setProperties(objIds, propertyMap) {
        console.error(`ERROR in ${this.apiName}.setProperties(): No model viewer instantiated.`)
        return Promise.reject("No model viewer instantiated");
    }

    /**
     * Create or update property type. Synchronizes with Infohub.
     * @param {object} propData - Property type definition.
     * @example * // Example propData objects:
                propData1 = {
                    name: "MyLength",
                    datatype: "xs:double",
                    unit: "m"
                }
                propData2 = {
                    name: "TrafficLight",
                    datatype: "xs:string",
                    values: ["red", "yellow", "green"]
                    readOnly: true
                }
     * @param {boolean} updateExisting - Whether to update existing type.
     * @returns {ApiResponse<boolean>}
     */
    createPropertyType(propData, updateExisting) {
        console.error(`ERROR in ${this.apiName}.createPropertyType(): No model viewer instantiated.`)
        return Promise.reject("No model viewer instantiated");
    }

    /**
     * Delete exsisting property type. Synchronizes with Infohub.
     * @param {string} ptKeyStr - Access key of property type in the format name##datatype.
     * @returns {ApiResponse<boolean>}
     */
    deletePropertyType(ptKeyStr) {
        console.error(`ERROR in ${this.apiName}.deletePropertyType(): No model viewer instantiated.`)
        return Promise.reject("No model viewer instantiated");
    }

    /**
     *
     * @param {object} settings {
     *       'scope_id'        : ' ... ',
     *       'project_shortid' : ' ... ',
     *       'connected_by'    : ' ... '
     *   }
     * @returns {ApiResponse<void>}
     * complies with COLNEOpro-API, 2025-10-14, ar
     */
    setInfohubSettings(settings) {
        console.error(`ERROR in ${this.apiName}.setInfohubSettings(): No model viewer instantiated.`)
        return Promise.reject("No model viewer instantiated");
    }

    /**
     *
     * @returns {object} settings object
     * @example {
     *       'scope_id'        : ' ... ',
     *       'project_shortid' : ' ... ',
     *       'connected_by'    : ' ... '
     *   }
     */
    getInfohubSettings() {
        console.error(`ERROR in ${this.apiName}.getInfohubSettings(): No model viewer instantiated.`)
        return Promise.reject("No model viewer instantiated");
    }

    // ======== Viewpoint Methods ========

    /**
     * Get list of all viewpoints.
     * @returns {ApiResponse<string[]>}
     * @since 10.2025
     */
    getViewpointIds() {
        console.error(`ERROR in ${this.apiName}.getViewpointIds(): No model viewer instantiated.`)
        return Promise.reject("No model viewer instantiated");
    }

    /**
     * Create a new viewpoint.
     * @param {string | null} parentId - ID of parent object
     * @param {object} options
     * @returns {ApiResponse<string>} ID of newly created viewpoint.
     */
    createViewpoint(parentId, options) {
        console.error(`ERROR in ${this.apiName}.createViewpoint(): No model viewer instantiated.`)
        return Promise.reject("No model viewer instantiated");
    }

    /**
     * Update existing viewpoint.
     * @param {string} objId - Object ID
     * @param {object} data - Data for the viewpoint in JSON notation
     * @returns {ApiResponse<boolean>} True if update was successful.
     * @since 10.2025
     */
    updateViewpoint(objId, data) {
        console.error(`ERROR in ${this.apiName}.updateViewpoint(): No model viewer instantiated.`)
        return Promise.reject("No model viewer instantiated");
    }

    /**
     * Activate a viewpoint.
     * @param {string} objId - Object ID
     * @returns {ApiResponse<boolean>} True if viewpoint was activated.
     */
    activateViewpoint(objId) {
        console.error(`ERROR in ${this.apiName}.activateViewpoint(): No model viewer instantiated.`)
        return Promise.reject("No model viewer instantiated");
    }

    /**
     * Get viewpoint data.
     * @param {string} objId - Object ID
     * @returns {ApiResponse<object>} JSON object with viewpoint data.
     */
    getViewpointData(objId) {
        console.error(`ERROR in ${this.apiName}.getViewpointData(): No model viewer instantiated.`)
        return Promise.reject("No model viewer instantiated");
    }

    /**
     * Set viewpoint data.
     * @param {string} objId - Object ID
     * @param {object} viewpointData - Viewpoint data to set.
     * @returns {ApiResponse<boolean>} True if viewpoint data was set.
     */
    setViewpointData(objId, viewpointData) {
        console.error(`ERROR in ${this.apiName}.setViewpointData(): No model viewer instantiated.`)
        return Promise.reject("No model viewer instantiated");
    }

    /**
     * Delete a viewpoint.
     * @param {string} objId - Object ID
     * @returns {ApiResponse<boolean>} True if viewpoint was deleted.
     */
    deleteViewpoint(objId) {
        console.error(`ERROR in ${this.apiName}.deleteViewpoint(): No model viewer instantiated.`)
        return Promise.reject("No model viewer instantiated");
    }

    // ======== Style / Material / Color Methods ========

    /**
     * Get list of Ids of all available styles.
     * @returns {ApiResponse<string[]>} Array of style object Ids.
     * @since 10.2025
     */
    getStyleIds() {
        console.error(`ERROR in ${this.apiName}.getStyleIds(): No model viewer instantiated.`)
        return Promise.reject("No model viewer instantiated");
    }

    /**
     * Get styles / materials / colors applied to given objects.
     * @param {string[]} objIDs - Object IDs.
     * @returns {ApiResponse<object[]>} Array of applied style / material objects.
     * @since 10.2025
     */
    getStyles(objIDs) {
        console.error(`ERROR in ${this.apiName}.getStyles(): No model viewer instantiated.`)
        return Promise.reject("No model viewer instantiated");
    }

    /**
     * Get information about specific style / material attributes.
     * @param {string} styleId - Style ID.
     * @param {string} key - If specified, only the corresponding attribute is returned, otherwise the entire object.
     * @returns {ApiResponse<object|string>} Style attribute info.
     * @since 10.2025
     */
    getStyleData(styleId, key) {
        console.error(`ERROR in ${this.apiName}.getStyleData(): No model viewer instantiated.`)
        return Promise.reject("No model viewer instantiated");
    }

    /**
     * Create a new style / material.
     * @param {object} styleData - Style definition.
     * @example * // Example styleData:
     * const styleData = {
            * id: "12345",        // optional
            * name: "MyStyle",    // not empty
            * color: "#rrggbbaa"  // valid color value in hexadecimal RGBA format
            * }
     * @returns {ApiResponse<string>} ID of newly created style.
     */
    createStyle(styleData) {
        console.error(`ERROR in ${this.apiName}.createStyle(): No model viewer instantiated.`)
        return Promise.reject("No model viewer instantiated");
    }

    /**
     * Update style / material.
     * @param {string} styleId - Style ID.
     * @param {object} styleData - Updated style data.
     * @returns {ApiResponse<boolean>} True if style was updated.
     */
    updateStyle(styleId, styleData) {
        console.error(`ERROR in ${this.apiName}.updateStyle(): No model viewer instantiated.`)
        return Promise.reject("No model viewer instantiated");
    }

    /**
     * Delete styles / materials.
     * @param {string[]} styleIds - IDs of styles to delete.
     * @returns {ApiResponse<boolean>} True if styles deleted.
     * @since 10.2025
     */
    deleteStyles(styleIds) {
        console.error(`ERROR in ${this.apiName}.deleteStyles(): No model viewer instantiated.`)
        return Promise.reject("No model viewer instantiated");
    }

    /**
     * Apply style to objects.
     * @param {string} styleId - Style ID.
     * @param {string[]} objIds - Object IDs.
     * @returns {ApiResponse<boolean>} True if objects style has been changed
     */
    applyStyleToObjects(styleId, objIds) {
        console.error(`ERROR in ${this.apiName}.applyStyleToObjects(): No model viewer instantiated.`)
        return Promise.reject("No model viewer instantiated");
    }

    /**
     * Reset styles to default.
     * @param {string[]} objIds - Object IDs.
     * @returns {ApiResponse<boolean>} True if reset succeeded. styles reset to default
     * @since 10.2025
     */
    resetStylesOfObjects(objIds) {
        console.error(`ERROR in ${this.apiName}.resetStylesOfObjects(): No model viewer instantiated.`)
        return Promise.reject("No model viewer instantiated");
    }


    // ======== SmartSet Methods ========

    /**
     * Create new SmartSet.
     * @param {string} parentId - Id of parent
     * @param {string} name - Name of the SmartSet.
     * @param {string[]|null} objectIds - List of object IDs (optional) which should be added as flat list to the SmartSet.
     * @returns {ApiResponse<string>} ID of newly created SmartSet.
     * @since 10.2025
     */
    createSmartSet(parentId, name, objectIds) {
        console.error(`ERROR in ${this.apiName}.createSmartSet(): No model viewer instantiated.`)
        return Promise.reject("No model viewer instantiated");
    }


    /**
     * Delete a SmartSet.
     * @param {string} smartSetId - Id of SmartSet.
     * @returns {ApiResponse<boolean>} True if deleted.
     * @since 10.2025
     */
    deleteSmartSet(smartSetId) {
        console.error(`ERROR in ${this.apiName}.deleteSmartSet(): No model viewer instantiated.`)
        return Promise.reject("No model viewer instantiated");
    }

    /**
     * Add objects to SmartSet.
     * @param {string} smartSetId - SmartSet ID.
     * @param {string[]} objIds - Object IDs.
     * @param {boolean} includeChildren - true: tree structure, false: flat list
     * @returns {ApiResponse<boolean>} True if objects effectivily added
     * @since 10.2025
     */
    addObjectsToSmartSet(smartSetId, objIds, includeChildren) {
        console.error(`ERROR in ${this.apiName}.addObjectsToSmartSet(): No model viewer instantiated.`)
        return Promise.reject("No model viewer instantiated");
    }

    /**
     * Remove objects from SmartSet.
     * @param {string} smartSetId - SmartSet ID.
     * @param {string[]} objIds - Object IDs to remove.
     * @returns {ApiResponse<boolean>} True if objects effectivily removed
     * @since 10.2025
     */
    removeObjectsFromSmartSet(smartSetId, objIds) {
        console.error(`ERROR in ${this.apiName}.removeObjectsFromSmartSet(): No model viewer instantiated.`)
        return Promise.reject("No model viewer instantiated");
    }

    /**
     * Create SmartSets from schema.
     * @param {object} schema - Schema definition.
     * @returns {ApiResponse<string[]>} Array of SmartSet IDs.
     */
    createSmartSetsFromSchema(schema) {
        console.error(`ERROR in ${this.apiName}.createSmartSetsFromSchema(): No model viewer instantiated.`)
        return Promise.reject("No model viewer instantiated");
    }

    /**
     * Update SmartSet. Synchronizes with Infohub.
     * @param {string} smartSetId - SmartSet ID.
     * @returns {ApiResponse<boolean>} True if SmartSet was updated.
     */
    updateSmartSet(smartSetId) {
        console.error(`ERROR in ${this.apiName}.updateSmartSet(): No model viewer instantiated.`)
        return Promise.reject("No model viewer instantiated");
    }

    /**
     * Add style to SmartSet.
     * @param {string} smartSetId - ID the SmartSet.
     * @param {object} options
     * @returns {ApiResponse<string>} ID of newly created style.
     * @since 10.2025
     */
    addStyleSchemaToSmartSet(smartSetId, options) {
        console.error(`ERROR in ${this.apiName}.addStyleSchemaToSmartSet(): No model viewer instantiated.`)
        return Promise.reject("No model viewer instantiated");
    }

    /**
     * Remove style from SmartSet.
     * @param {string} smartSetId - ID the SmartSet.
     * @returns {ApiResponse<boolean>} True if successfully removed.
     * @since 10.2025
     */
    removeStyleSchemaFromSmartSet(smartSetId) {
        console.error(`ERROR in ${this.apiName}.removeStyleSchemaFromSmartSet(): No model viewer instantiated.`)
        return Promise.reject("No model viewer instantiated");
    }

    /**
     * Activate style schema scheme.
     * @param {string} smartSetId - ID the SmartSet.
     * @returns {ApiResponse<boolean>} True if successfully activated.
     * @since 10.2025
     */
    activateStyleSchemaScheme(smartSetId) {
        console.error(`ERROR in ${this.apiName}.activateStyleSchemaScheme(): No model viewer instantiated.`)
        return Promise.reject("No model viewer instantiated");
    }

    /**
     * Add viewpoint to SmartSet.
     * @param {string} smartSetId - ID the SmartSet.
     * @param {object} options
     * @returns {ApiResponse<status>}
     * @since 10.2025
     */
    addViewpointToSmartSet(smartSetId, options) {
        console.error(`ERROR in ${this.apiName}.addViewpointToSmartSet(): No model viewer instantiated.`)
        return Promise.reject("No model viewer instantiated");
    }

    /**
     * remove viewpoint to SmartSet.
     * @param {string} smartSetId - ID the SmartSet.
     * @returns {ApiResponse<boolean>} True if successfully removed.
     * @since 10.2025
     */
    removeViewpointFromSmartSet(smartSetId) {
        console.error(`ERROR in ${this.apiName}.removeViewpointFromSmartSet(): No model viewer instantiated.`)
        return Promise.reject("No model viewer instantiated");
    }

    /**
     * 
     * Open URL/Link in Browser (target = null -> default browser )
     * 
     * @param {*} url 
     * @param {*} target     
     */
    openUrl(url,target) {
        console.error(`ERROR in ${this.apiName}.openUrl(): No model viewer instantiated.`)
        return Promise.reject("No model viewer instantiated");
    }

}