/** * @desc A {@link Viewer} plugin that provides methods for visualizing IfcBuildingStoreys. * * * * [[Run this example](https://xeokit.github.io/xeokit-sdk/examples/#storeyViews_StoreyViewsPlugin_recipe2)] * * ## Overview * * StoreyViewsPlugin provides a flexible set of methods for visualizing building storeys in 3D and 2D. * * Use the first two methods to set up 3D views of storeys: * * * [showStoreyObjects](#instance-method-showStoreyObjects) - shows the {@link Entity}s within a storey, and * * [gotoStoreyCamera](#instance-method-gotoStoreyCamera) - positions the {@link Camera} for a plan view of the Entitys within a storey. *

* * Use the second two methods to create 2D plan view mini-map images: * * * [createStoreyMap](#instance-method-createStoreyMap) - creates a 2D plan view image of a storey, and * * [pickStoreyMap](#instance-method-pickStoreyMap) - picks the {@link Entity} at the given 2D pixel coordinates within a plan view image. * * ## Usage * * Let's start by creating a {@link Viewer} with a StoreyViewsPlugin and an {@link XKTLoaderPlugin}. * * Then we'll load a BIM building model from an ```.xkt``` file. * * ````javascript * import {Viewer, XKTLoaderPlugin, StoreyViewsPlugin} from "xeokit-sdk.es.js"; * * // Create a Viewer, arrange the camera * * const viewer = new Viewer({ * canvasId: "myCanvas", * transparent: true * }); * * viewer.camera.eye = [-2.56, 8.38, 8.27]; * viewer.camera.look = [13.44, 3.31, -14.83]; * viewer.camera.up = [0.10, 0.98, -0.14]; * * // Add an XKTLoaderPlugin * * const xktLoader = new XKTLoaderPlugin(viewer); * * // Add a StoreyViewsPlugin * * const storeyViewsPlugin = new StoreyViewsPlugin(viewer); * * // Load a BIM model from .xkt format * * const model = xktLoader.load({ * id: "myModel", * src: "./models/xkt/Schependomlaan.xkt", * edges: true * }); * ```` * * ## Finding Storeys * * Getting information on a storey in our model: * * ````javascript * const storey = storeyViewsPlugin.storeys["2SWZMQPyD9pfT9q87pgXa1"]; // ID of the IfcBuildingStorey * * const modelId = storey.modelId; // "myModel" * const storeyId = storey.storeyId; // "2SWZMQPyD9pfT9q87pgXa1" * const aabb = storey.aabb; // Axis-aligned 3D World-space boundary of the IfcBuildingStorey * ```` * * We can also get a "storeys" event every time the set of storeys changes, ie. every time a storey is created or destroyed: * * ````javascript * storeyViewsPlugin.on("storeys", ()=> { * const storey = storeyViewsPlugin.storeys["2SWZMQPyD9pfT9q87pgXa1"]; * //... * }); * ```` * * ## Showing Entitys within Storeys * * Showing the {@link Entity}s within a storey: * * ````javascript * storeyViewsPlugin.showStoreyObjects("2SWZMQPyD9pfT9q87pgXa1"); * ```` * * Showing **only** the Entitys in a storey, hiding all others: * * ````javascript * storeyViewsPlugin.showStoreyObjects("2SWZMQPyD9pfT9q87pgXa1", { * hideOthers: true * }); * ```` * Showing only the storey Entitys, applying custom appearances configured on {@link StoreyViewsPlugin#objectStates}: * * ````javascript * storeyViewsPlugin.showStoreyObjects("2SWZMQPyD9pfT9q87pgXa1", { * hideOthers: true, * useObjectStates: true * }); * ```` * * * * [[Run this example](https://xeokit.github.io/xeokit-sdk/examples/#storeyViews_StoreyViewsPlugin_showStoreyObjects)] * * When using this option, at some point later you'll probably want to restore all Entitys to their original visibilities and * appearances. * * To do that, save their visibility and appearance states in an {@link ObjectsMemento} beforehand, from * which you can restore them later: * * ````javascript * const objectsMemento = new ObjectsMemento(); * * // Save all Entity visibility and appearance states * * objectsMemento.saveObjects(viewer.scene); * * // Show storey view Entitys, with custom appearances as configured for IFC types * * storeyViewsPlugin.showStoreyObjects("2SWZMQPyD9pfT9q87pgXa1", { * useObjectStates: true // <<--------- Apply custom appearances * }); * * //... * * // Later, restore all Entitys to their saved visibility and appearance states * objectsMemento.restoreObjects(viewer.scene); * ```` * * ## Arranging the Camera for Storey Plan Views * * The {@link StoreyViewsPlugin#gotoStoreyCamera} method positions the {@link Camera} for a plan view of * the {@link Entity}s within the given storey. * * * * [[Run this example](https://xeokit.github.io/xeokit-sdk/examples/#storeyViews_StoreyViewsPlugin_gotoStoreyCamera)] * * Let's fly the {@link Camera} to a downward-looking orthographic view of the Entitys within our storey. * * ````javascript * storeyViewsPlugin.gotoStoreyCamera("2SWZMQPyD9pfT9q87pgXa1", { * projection: "ortho", // Orthographic projection * duration: 2.5, // 2.5 second transition * done: () => { * viewer.cameraControl.planView = true; // Disable rotation * } * }); * ```` * * Note that we also set {@link CameraControl#planView} ````true````, which prevents the CameraControl from rotating * or orbiting. In orthographic mode, this effectively makes the {@link Viewer} behave as if it were a 2D viewer, with * picking, panning and zooming still enabled. * * If you need to be able to restore the Camera to its previous state, you can save it to a {@link CameraMemento} * beforehand, from which you can restore it later: * * ````javascript * const cameraMemento = new CameraMemento(); * * // Save camera state * * cameraMemento.saveCamera(viewer.scene); * * // Position camera for a downward-looking orthographic view of our storey * * storeyViewsPlugin.gotoStoreyCamera("2SWZMQPyD9pfT9q87pgXa1", { * projection: "ortho", * duration: 2.5, * done: () => { * viewer.cameraControl.planView = true; // Disable rotation * } * }); * * //... * * // Later, restore the Camera to its saved state * cameraMemento.restoreCamera(viewer.scene); * ```` * * ## Creating StoreyMaps * * The {@link StoreyViewsPlugin#createStoreyMap} method creates a 2D orthographic plan image of the given storey. * * * * [[Run this example](https://xeokit.github.io/xeokit-sdk/examples/#storeyViews_StoreyViewsPlugin_createStoreyMap)] * * This method creates a {@link StoreyMap}, which provides the plan image as a Base64-encoded string. * * Let's create a 2D plan image of our building storey: * * ````javascript * const storeyMap = storeyViewsPlugin.createStoreyMap("2SWZMQPyD9pfT9q87pgXa1", { * width: 300, * format: "png" * }); * * const imageData = storeyMap.imageData; // Base64-encoded image data string * const width = storeyMap.width; // 300 * const height = storeyMap.height; // Automatically derived from width * const format = storeyMap.format; // "png" * ```` * * As with ````showStoreyEntitys````, We also have the option to customize the appearance of the Entitys in our plan * images according to their IFC types, using the lookup table configured on {@link StoreyViewsPlugin#objectStates}. * * For example, we usually want to show only element types like ````IfcWall````, ````IfcDoor```` and * ````IfcFloor```` in our plan images. * * Let's create another StoreyMap, this time applying the custom appearances: * * ````javascript * const storeyMap = storeyViewsPlugin.createStoreyMap("2SWZMQPyD9pfT9q87pgXa1", { * width: 300, * format: "png", * useObjectStates: true // <<--------- Apply custom appearances * }); *```` * * We can also specify a ````height```` for the plan image, as an alternative to ````width````: * * ````javascript * const storeyMap = storeyViewsPlugin.createStoreyMap("2SWZMQPyD9pfT9q87pgXa1", { * height: 200, * format: "png", * useObjectStates: true * }); * ```` * * ## Picking Entities in StoreyMaps * * We can use {@link StoreyViewsPlugin#pickStoreyMap} to pick Entities in our building storey, using 2D coordinates from mouse or touch events on our {@link StoreyMap}'s 2D plan image. * * * * [[Run this example](https://xeokit.github.io/xeokit-sdk/examples/#storeyViews_StoreyViewsPlugin_recipe2)] * * Let's programmatically pick the Entity at the given 2D pixel coordinates within our image: * * ````javascript * const mouseCoords = [65, 120]; // Mouse coords within the image extents * * const pickResult = storeyViewsPlugin.pickStoreyMap(storeyMap, mouseCoords); * * if (pickResult && pickResult.entity) { * pickResult.entity.highlighted = true; * } * ```` */ export class StoreyViewsPlugin extends Plugin { /** * @constructor * * @param {Viewer} viewer The Viewer. * @param {Object} cfg Plugin configuration. * @param {String} [cfg.id="StoreyViews"] Optional ID for this plugin, so that we can find it within {@link Viewer#plugins}. * @param {Object} [cfg.objectStates] Map of visual states for the {@link Entity}s as rendered within each {@link Storey}. Default value is {@link IFCStoreyPlanObjectStates}. */ constructor(viewer: any, cfg?: { id?: string; objectStates?: any; }); _objectsMemento: ObjectsMemento; _cameraMemento: CameraMemento; /** * A {@link Storey} for each ````IfcBuildingStorey```. * * There will be a {@link Storey} for every existing {@link MetaObject} whose {@link MetaObject#type} equals "IfcBuildingStorey". * * These are created and destroyed automatically as models are loaded and destroyed. * * @type {{String:Storey}} */ storeys: { String: Storey; }; /** * A set of {@link Storey}s for each {@link MetaModel}. * * These are created and destroyed automatically as models are loaded and destroyed. * * @type {{String: {String:Storey}}} */ modelStoreys: { String: { String: Storey; }; }; /** * Sets map of visual states for the {@link Entity}s as rendered within each {@link Storey}. * * Default value is {@link IFCStoreyPlanObjectStates}. * * @type {{String: Object}} */ set objectStates(arg: { String: any; }); /** * Gets map of visual states for the {@link Entity}s as rendered within each {@link Storey}. * * Default value is {@link IFCStoreyPlanObjectStates}. * * @type {{String: Object}} */ get objectStates(): { String: any; }; _onModelLoaded: any; _registerModelStoreys(modelId: any): void; _deregisterModelStoreys(modelId: any): void; _objectStates: { String: any; }; /** * Arranges the {@link Camera} for a 3D orthographic view of the {@link Entity}s within the given storey. * * See also: {@link CameraMemento}, which saves and restores the state of the {@link Scene}'s {@link Camera} * * @param {String} storeyId ID of the ````IfcBuildingStorey```` object. * @param {*} [options] Options for arranging the Camera. * @param {String} [options.projection] Projection type to transition the Camera to. Accepted values are "perspective" and "ortho". * @param {Function} [options.done] Callback to fire when the Camera has arrived. When provided, causes an animated flight to the saved state. Otherwise jumps to the saved state. */ gotoStoreyCamera(storeyId: string, options?: any): void; /** * Shows the {@link Entity}s within the given storey. * * Optionally hides all other Entitys. * * Optionally sets the visual appearance of each of the Entitys according to its IFC type. The appearance of * IFC types in plan views is configured by {@link StoreyViewsPlugin#objectStates}. * * See also: {@link ObjectsMemento}, which saves and restores a memento of the visual state * of the {@link Entity}'s that represent objects within a {@link Scene}. * * @param {String} storeyId ID of the ````IfcBuildingStorey```` object. * @param {*} [options] Options for showing the Entitys within the storey. * @param {Boolean} [options.hideOthers=false] When ````true````, hide all other {@link Entity}s. * @param {Boolean} [options.useObjectStates=false] When ````true````, apply the custom visibilities and appearances configured for IFC types in {@link StoreyViewsPlugin#objectStates}. */ showStoreyObjects(storeyId: string, options?: any): void; /** * Executes a callback on each of the objects within the given storey. * * ## Usage * * In the example below, we'll show all the {@link Entity}s, within the given ````IfcBuildingStorey````, * that have {@link MetaObject}s with type ````IfcSpace````. Note that the callback will only be given * an {@link Entity} when one exists for the given {@link MetaObject}. * * ````JavaScript * myStoreyViewsPlugin.withStoreyObjects(storeyId, (entity, metaObject) => { * if (entity && metaObject && metaObject.type === "IfcSpace") { * entity.visible = true; * } * }); * ```` * * @param {String} storeyId ID of the ````IfcBuildingStorey```` object. * @param {Function} callback The callback. */ withStoreyObjects(storeyId: string, callback: Function): void; /** * Creates a 2D map of the given storey. * * @param {String} storeyId ID of the ````IfcBuildingStorey```` object. * @param {*} [options] Options for creating the image. * @param {Number} [options.width=300] Image width in pixels. Height will be automatically determined from this, if not given. * @param {Number} [options.height=300] Image height in pixels, as an alternative to width. Width will be automatically determined from this, if not given. * @param {String} [options.format="png"] Image format. Accepted values are "png" and "jpeg". * @returns {StoreyMap} The StoreyMap. */ createStoreyMap(storeyId: string, options?: any): StoreyMap; _arrangeStoreyMapCamera(storey: any): void; /** * Attempts to pick an {@link Entity} at the given pixel coordinates within a StoreyMap image. * * @param {StoreyMap} storeyMap The StoreyMap. * @param {Number[]} imagePos 2D pixel coordinates within the bounds of {@link StoreyMap#imageData}. * @param {*} [options] Picking options. * @param {Boolean} [options.pickSurface=false] Whether to return the picked position on the surface of the Entity. * @returns {PickResult} The pick result, if an Entity was successfully picked, else null. */ pickStoreyMap(storeyMap: StoreyMap, imagePos: number[], options?: any): any; /** * Gets the ID of the storey that contains the given 3D World-space position. *. * @param {Number[]} worldPos 3D World-space position. * @returns {String} ID of the storey containing the position, or null if the position falls outside all the storeys. */ getStoreyContainingWorldPos(worldPos: number[]): string; /** * Converts a 3D World-space position to a 2D position within a StoreyMap image. * * Use {@link StoreyViewsPlugin#pickStoreyMap} to convert 2D image positions to 3D world-space. * * @param {StoreyMap} storeyMap The StoreyMap. * @param {Number[]} worldPos 3D World-space position within the storey. * @param {Number[]} imagePos 2D pixel position within the {@link StoreyMap#imageData}. * @returns {Boolean} True if ````imagePos```` is within the bounds of the {@link StoreyMap#imageData}, else ````false```` if it falls outside. */ worldPosToStoreyMap(storeyMap: StoreyMap, worldPos: number[], imagePos: number[]): boolean; /** * Converts a 3D World-space direction vector to a 2D vector within a StoreyMap image. * * @param {StoreyMap} storeyMap The StoreyMap. * @param {Number[]} worldDir 3D World-space direction vector. * @param {Number[]} imageDir Normalized 2D direction vector. */ worldDirToStoreyMap(storeyMap: StoreyMap, worldDir: number[], imageDir: number[]): void; } import { Plugin } from "../../viewer/Plugin.js"; import { ObjectsMemento } from "../../viewer/scene/mementos/ObjectsMemento.js"; import { CameraMemento } from "../../viewer/scene/mementos/CameraMemento.js"; import { Storey } from "./Storey.js"; import { StoreyMap } from "./StoreyMap.js";