@xtctwins/tctwins-bimx-viewer 0.1.3 → 0.1.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -44,7 +44,7 @@ eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpac
44
44
  \***************************/
45
45
  /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
46
46
 
47
- eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"default\": () => (/* binding */ BIMXViewer)\n/* harmony export */ });\n/* harmony import */ var _xtctwins_tctwins_core__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @xtctwins/tctwins-core */ \"./node_modules/@xtctwins/tctwins-core/dist/tctwins-core.es5.js\");\n/* harmony import */ var _messages__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./messages */ \"./src/messages.ts\");\n/* harmony import */ var _EventTrigger__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./EventTrigger */ \"./src/EventTrigger.ts\");\n/* harmony import */ var _Controller__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./Controller */ \"./src/Controller.ts\");\n/* harmony import */ var _toolbar_ResetAction__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./toolbar/ResetAction */ \"./src/toolbar/ResetAction.ts\");\n/* harmony import */ var _toolbar_FitAction__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ./toolbar/FitAction */ \"./src/toolbar/FitAction.ts\");\n/* harmony import */ var _toolbar_FirstPersonMode__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ./toolbar/FirstPersonMode */ \"./src/toolbar/FirstPersonMode.ts\");\n/* harmony import */ var _toolbar_HideTool__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! ./toolbar/HideTool */ \"./src/toolbar/HideTool.ts\");\n/* harmony import */ var _toolbar_ShowSpacesMode__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! ./toolbar/ShowSpacesMode */ \"./src/toolbar/ShowSpacesMode.ts\");\n/* harmony import */ var _toolbar_SectionTool__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(/*! ./toolbar/SectionTool */ \"./src/toolbar/SectionTool.ts\");\n/* harmony import */ var _toolbar_NavCubeMode__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(/*! ./toolbar/NavCubeMode */ \"./src/toolbar/NavCubeMode.ts\");\n/* harmony import */ var _explorer_ModelsExplorer__WEBPACK_IMPORTED_MODULE_11__ = __webpack_require__(/*! ./explorer/ModelsExplorer */ \"./src/explorer/ModelsExplorer.ts\");\n/* harmony import */ var _explorer_ObjectsExplorer__WEBPACK_IMPORTED_MODULE_12__ = __webpack_require__(/*! ./explorer/ObjectsExplorer */ \"./src/explorer/ObjectsExplorer.ts\");\n/* harmony import */ var _explorer_ClassesExplorer__WEBPACK_IMPORTED_MODULE_13__ = __webpack_require__(/*! ./explorer/ClassesExplorer */ \"./src/explorer/ClassesExplorer.ts\");\n/* harmony import */ var _explorer_StoreysExplorer__WEBPACK_IMPORTED_MODULE_14__ = __webpack_require__(/*! ./explorer/StoreysExplorer */ \"./src/explorer/StoreysExplorer.ts\");\n/* harmony import */ var _toolbar_ThreeDMode__WEBPACK_IMPORTED_MODULE_15__ = __webpack_require__(/*! ./toolbar/ThreeDMode */ \"./src/toolbar/ThreeDMode.ts\");\n/* harmony import */ var _toolbar_OrthoMode__WEBPACK_IMPORTED_MODULE_16__ = __webpack_require__(/*! ./toolbar/OrthoMode */ \"./src/toolbar/OrthoMode.ts\");\n/* harmony import */ var _collision_ObjectsKdTree3__WEBPACK_IMPORTED_MODULE_17__ = __webpack_require__(/*! ./collision/ObjectsKdTree3 */ \"./src/collision/ObjectsKdTree3.ts\");\n/* harmony import */ var _toolbar_AnnotationTool__WEBPACK_IMPORTED_MODULE_18__ = __webpack_require__(/*! ./toolbar/AnnotationTool */ \"./src/toolbar/AnnotationTool.ts\");\n/* harmony import */ var _toolbar_MeasureTool__WEBPACK_IMPORTED_MODULE_19__ = __webpack_require__(/*! ./toolbar/MeasureTool */ \"./src/toolbar/MeasureTool.ts\");\n/* harmony import */ var _toolbar_CommentsTool__WEBPACK_IMPORTED_MODULE_20__ = __webpack_require__(/*! ./toolbar/CommentsTool */ \"./src/toolbar/CommentsTool.ts\");\n/* harmony import */ var _server_Server__WEBPACK_IMPORTED_MODULE_21__ = __webpack_require__(/*! ./server/Server */ \"./src/server/Server.ts\");\nvar __awaiter = (undefined && undefined.__awaiter) || function (thisArg, _arguments, P, generator) {\n function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }\n return new (P || (P = Promise))(function (resolve, reject) {\n function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }\n function rejected(value) { try { step(generator[\"throw\"](value)); } catch (e) { reject(e); } }\n function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }\n step((generator = generator.apply(thisArg, _arguments || [])).next());\n });\n};\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n/**\n * 核心模型视图窗口\n * @type {BIMViewer}\n */\nclass BIMXViewer extends _Controller__WEBPACK_IMPORTED_MODULE_3__[\"default\"] {\n /**\n * Constructs a BIMViewer.\n * @param {Server} server Data access strategy.\n * @param {*} cfg Configuration.\n * @param {Boolean} [cfg.enableEditModels=false] Set ````true```` to show \"Add\", \"Edit\" and \"Delete\" options in the Models tab's context menu.\n * @param {Boolean} [cfg.keyboardEventsElement] Optional reference to HTML element on which key events should be handled. Defaults to the HTML Document.\n */\n constructor(cfg = {}) {\n if (!cfg.canvasElement) {\n throw new Error(\"Config expected: canvasElement\");\n }\n if (!cfg.navCubeCanvasElement) {\n throw new Error(\"Config expected: navCubeCanvasElement\");\n }\n const { canvasElement } = cfg;\n const { viewerElement } = cfg;\n const localeService = new _xtctwins_tctwins_core__WEBPACK_IMPORTED_MODULE_0__.LocaleService({\n messages: _messages__WEBPACK_IMPORTED_MODULE_1__[\"default\"],\n locale: \"ch\"\n });\n const viewer = new _xtctwins_tctwins_core__WEBPACK_IMPORTED_MODULE_0__.Viewer({\n passes: 5,\n localeService,\n canvasElement,\n viewerElement,\n transparent: true,\n alphaDepthMask: true,\n backgroundColorFromAmbientLight: true,\n snapRadius: cfg.snapRadius,\n antialias: true,\n saoEnabled: false,\n pbrEnabled: true,\n dtxEnabled: true,\n edgesEnabled: true,\n colorTextureEnabled: true,\n premultipliedAlpha: true,\n resolutionScale: window.devicePixelRatio,\n spinnerElementId: \"engine_spinner\"\n });\n const server = new _server_Server__WEBPACK_IMPORTED_MODULE_21__[\"default\"]({\n dataDir: \"./data\",\n filePath: \"testdemo\"\n });\n super(null, cfg, server, viewer);\n /** 是否是聚焦分布模式 */\n this._focusPartial = false;\n /** 根据构建检测检测得到的构建分布字符串数组结果 */\n this._partialObjectIds = [];\n /** 当前聚焦的分布索引 */\n this._partialFocusIndex = 0;\n /** 是否已加载metadata */\n this._metaLoaded = false;\n /**\n * 按照指定角度旋转相机\n * @param {number} angleInc\n * @returns\n */\n this.orbitYawCamera = (angleInc) => {\n return new Promise((resolve, reject) => {\n try {\n this.viewer.scene.camera.orbitYaw(angleInc);\n resolve(); // 执行成功时调用 resolve\n }\n catch (error) {\n reject(error); // 发生错误时调用 reject\n }\n });\n };\n this.cameraEnable = (pointerEnabled = !this.viewer.cameraControl.pointerEnabled) => {\n this.viewer.cameraControl.pointerEnabled = pointerEnabled;\n };\n /**\n * 模型截图\n * @param width\n * @param height\n * @param isDownload\n * @returns\n */\n this.shot = (width, height, isDownload) => {\n const canvas = document.getElementById(\"myCanvas\");\n const link = document.createElement(\"a\");\n link.download = \"screenshot.png\";\n const tempCanvas = document.createElement(\"canvas\");\n console.log(\"tempCanvas\", tempCanvas);\n const tempCtx = tempCanvas.getContext(\"2d\");\n if (canvas && tempCtx) {\n tempCanvas.width = width;\n tempCanvas.height = height;\n const scaleX = width / canvas.width;\n const scaleY = height / canvas.height;\n const scale = Math.max(scaleX, scaleY);\n const scaledWidth = canvas.width * scale;\n const scaledHeight = canvas.height * scale;\n const offsetX = (width - scaledWidth) / 2;\n const offsetY = (height - scaledHeight) / 2;\n tempCtx.clearRect(0, 0, width, height);\n tempCtx.fillStyle = \"transparent\"; // 设置透明色\n tempCtx.fillRect(0, 0, width, height);\n tempCtx.drawImage(canvas, 0, 0, canvas.width, canvas.height, 0, 0, 1, 1);\n // tempCtx.drawImage(canvas, 0, 0, canvas.width, canvas.height, offsetX, offsetY, scaledWidth, scaledHeight);\n if (isDownload) {\n tempCanvas.toBlob(function (blob) {\n const url = URL.createObjectURL(blob);\n link.href = url;\n link.click();\n URL.revokeObjectURL(url);\n });\n }\n return tempCanvas.toDataURL(\"image/png\");\n }\n return \"\";\n };\n this._configs = {};\n this._eventTrigger = new _EventTrigger__WEBPACK_IMPORTED_MODULE_2__[\"default\"]();\n this.navCubeCanvasElement = cfg.navCubeCanvasElement;\n this.viewerElement = cfg.viewerElement;\n this._modelId = cfg.modelId;\n this._hasOutlier = false;\n this._outlierObjectIds = [];\n this.navCubeCanvasElement.oncontextmenu = (e) => {\n e.preventDefault();\n };\n this.viewer = viewer;\n this._objectsKdTree3 = new _collision_ObjectsKdTree3__WEBPACK_IMPORTED_MODULE_17__[\"default\"]({\n viewer\n });\n this._customizeViewer();\n this._modelsExplorer = new _explorer_ModelsExplorer__WEBPACK_IMPORTED_MODULE_11__[\"default\"](this, {\n enableEditModels: false,\n modelFromOutSide: true,\n modelType: cfg.modelType,\n modelContent: cfg.modelContent,\n modelSrc: cfg.modelSrc ? cfg.modelSrc : \"/\",\n modelMetaData: cfg.modelMetaData,\n modelConfig: cfg.modelConfig,\n IfcAPI: cfg.IfcAPI,\n WebIFC: cfg.WebIFC\n });\n this._objectsExplorer = new _explorer_ObjectsExplorer__WEBPACK_IMPORTED_MODULE_12__[\"default\"](this, {\n modelType: cfg.modelType\n });\n this._classesExplorer = new _explorer_ClassesExplorer__WEBPACK_IMPORTED_MODULE_13__[\"default\"](this, {\n modelType: cfg.modelType\n });\n this._storeysExplorer = new _explorer_StoreysExplorer__WEBPACK_IMPORTED_MODULE_14__[\"default\"](this, {\n modelType: cfg.modelType\n });\n // 重置相机视角的按钮(小房子图标)\n this._resetAction = new _toolbar_ResetAction__WEBPACK_IMPORTED_MODULE_4__[\"default\"](this, {});\n // 将相机视角放到最合适的位置的图标\n this._fitAction = new _toolbar_FitAction__WEBPACK_IMPORTED_MODULE_5__[\"default\"](this, {});\n // Allows Three-D and First Person toggle buttons to cooperatively switch\n // CameraControl#navMode between \"orbit\", \"firstPerson\" and \"planView\" modes\n class NavModeMediator {\n constructor(bimViewer) {\n this.threeDActive = false;\n this.firstPersonActive = false;\n this.setThreeDModeActive = (active) => {\n if (active) {\n bimViewer._firstPersonMode.setActive(false);\n bimViewer.viewer.cameraControl.navMode = \"orbit\";\n }\n else {\n bimViewer._firstPersonMode.setActive(false);\n bimViewer.viewer.cameraControl.navMode = \"planView\";\n }\n this.threeDActive = active;\n };\n this.setFirstPersonModeActive = (active) => {\n bimViewer.viewer.cameraControl.navMode = active ? \"firstPerson\" : this.threeDActive ? \"orbit\" : \"planView\";\n this.firstPersonActive = active;\n };\n }\n }\n const cameraControlNavModeMediator = new NavModeMediator(this);\n this._threeDMode = new _toolbar_ThreeDMode__WEBPACK_IMPORTED_MODULE_15__[\"default\"](this, {\n cameraControlNavModeMediator\n });\n this._orthoMode = new _toolbar_OrthoMode__WEBPACK_IMPORTED_MODULE_16__[\"default\"](this, {});\n this._firstPersonMode = new _toolbar_FirstPersonMode__WEBPACK_IMPORTED_MODULE_6__[\"default\"](this, {\n cameraControlNavModeMediator\n });\n this._hideTool = new _toolbar_HideTool__WEBPACK_IMPORTED_MODULE_7__[\"default\"](this, {});\n this._annotationTool = new _toolbar_AnnotationTool__WEBPACK_IMPORTED_MODULE_18__[\"default\"](this, {\n modelId: this._modelId\n });\n this._measureTool = new _toolbar_MeasureTool__WEBPACK_IMPORTED_MODULE_19__[\"default\"](this, {});\n this._sectionTool = new _toolbar_SectionTool__WEBPACK_IMPORTED_MODULE_9__[\"default\"](this, {});\n this._commentsTool = new _toolbar_CommentsTool__WEBPACK_IMPORTED_MODULE_20__[\"default\"](this, {});\n this._showSpacesMode = new _toolbar_ShowSpacesMode__WEBPACK_IMPORTED_MODULE_8__[\"default\"](this, {});\n this._navCubeMode = new _toolbar_NavCubeMode__WEBPACK_IMPORTED_MODULE_10__[\"default\"](this, {\n navCubeCanvasElement: this.navCubeCanvasElement,\n viewerElement: this.viewerElement\n });\n this._threeDMode.setActive(true);\n this._firstPersonMode.setActive(false);\n this._navCubeMode.setActive(true);\n this._annotationTool.setActive(false);\n this._measureTool.setActive(false);\n this._modelsExplorer.on(\"modelLoaded\", (modelId) => {\n this.fire(\"modelLoaded\", modelId);\n });\n this._modelsExplorer.on(\"modelUnloaded\", (modelId) => {\n this.fire(\"modelUnloaded\", modelId);\n });\n this._resetAction.on(\"reset\", () => {\n this.fire(\"reset\", true);\n });\n this._mutexActivation([this._hideTool, this._sectionTool, this._annotationTool]);\n this._bcfViewpointsPlugin = new _xtctwins_tctwins_core__WEBPACK_IMPORTED_MODULE_0__.BCFViewpointsPlugin(this.viewer, {});\n this._initConfigs();\n this._initSingleClickEvent();\n this._initRightClickEvent();\n this._initDoubleClickEvent();\n let treeReady = 0;\n this.eventTrigger.on(\"treeReady\", () => {\n treeReady++;\n if (treeReady === 3) {\n this.eventTrigger.emit(\"treeAllReady\", {\n objectsData: this.objectsExplorer.rootNode,\n classesData: this.classesExplorer.rootNode,\n storeysData: this.storeysExplorer.rootNode\n });\n }\n });\n }\n //------------------------------------------------------------------------------------------------------------------\n // 信息和服务\n //------------------------------------------------------------------------------------------------------------------\n get eventTrigger() {\n return this._eventTrigger;\n }\n /**\n * Returns the LocaleService that was configured on this Viewer.\n *\n * @return {LocaleService} The LocaleService.\n */\n get localeService() {\n return this.viewer.localeService;\n }\n //------------------------------------------------------------------------------------------------------------------\n // 点击事件\n //------------------------------------------------------------------------------------------------------------------\n /**\n * 初始化单击事件\n */\n _initSingleClickEvent() {\n this.viewer.cameraControl.on(\"mouseDownEntity\", (e) => {\n if (this.measureAngleTool.getActive() || this.measureDistanceTool.getActive())\n return;\n if (this.sectionTool.getActive() || this.annotationTool.getActive())\n return;\n e.preventDefault;\n const hit = this.viewer.scene.pick({\n canvasPos: e.canvasPos\n });\n if (hit) {\n if (hit.entity) {\n this.singleChoseEntity(hit.entity);\n this._eventTrigger.emit(\"pickedEntity\", hit.entity);\n }\n }\n });\n this.viewer.cameraControl.on(\"mouseDownNothing\", () => {\n if (this.measureAngleTool.getActive() || this.measureDistanceTool.getActive())\n return;\n if (this.sectionTool.getActive() || this.annotationTool.getActive())\n return;\n this.singleChosedSpace();\n this._eventTrigger.emit(\"pickedNothing\");\n });\n this.viewer.cameraControl.on(\"touchPicked\", (e) => {\n if (this.measureAngleTool.getActive() || this.measureDistanceTool.getActive())\n return;\n if (this.sectionTool.getActive() || this.annotationTool.getActive())\n return;\n e.preventDefault;\n const hit = this.viewer.scene.pick({\n canvasPos: e.canvasPos\n });\n if (hit) {\n if (hit.entity) {\n this.singleChoseEntity(hit.entity);\n this._eventTrigger.emit(\"touchEntity\", hit.entity);\n }\n }\n });\n this.viewer.cameraControl.on(\"touchPickedNothing\", () => {\n if (this.measureAngleTool.getActive() || this.measureDistanceTool.getActive())\n return;\n if (this.sectionTool.getActive() || this.annotationTool.getActive())\n return;\n this.singleChosedSpace();\n this._eventTrigger.emit(\"pickedNothing\");\n });\n }\n /**\n * 初始化右键事件\n */\n _initRightClickEvent() {\n this.viewer.cameraControl.on(\"rightClick\", (e) => {\n e.preventDefault;\n const hit = this.viewer.scene.pick({\n canvasPos: e.canvasPos\n });\n if (hit)\n this._eventTrigger.emit(\"rightPicked\", hit.entity);\n else {\n this._eventTrigger.emit(\"rightPickedNothing\");\n }\n });\n }\n /**\n * 初始化双击事件\n */\n _initDoubleClickEvent() {\n this.viewer.cameraControl.on(\"doublePicked\", (e) => {\n if (this.measureAngleTool.getActive() || this.measureDistanceTool.getActive())\n return;\n if (this.sectionTool.getActive() || this.annotationTool.getActive())\n return;\n e.preventDefault;\n const hit = this.viewer.scene.pick({\n canvasPos: e.canvasPos\n });\n if (hit) {\n if (hit.entity) {\n this.doubleChoseEntity(hit.entity);\n this._eventTrigger.emit(\"doublePicked\", hit.entity);\n }\n }\n });\n this.viewer.cameraControl.on(\"doublePickedNothing\", () => {\n if (this.measureAngleTool.getActive() || this.measureDistanceTool.getActive())\n return;\n if (this.sectionTool.getActive() || this.annotationTool.getActive())\n return;\n this.choseSpace();\n this._eventTrigger.emit(\"doublePickedNothing\");\n });\n }\n //------------------------------------------------------------------------------------------------------------------\n // 配置\n //------------------------------------------------------------------------------------------------------------------\n _customizeViewer() {\n const { scene } = this.viewer;\n // Emphasis effects\n scene.xrayMaterial.fill = false;\n scene.xrayMaterial.fillAlpha = 0.3;\n scene.xrayMaterial.fillColor = [0, 0, 0];\n scene.xrayMaterial.edges = true;\n scene.xrayMaterial.edgeAlpha = 0.1;\n scene.xrayMaterial.edgeColor = [0, 0, 0];\n // scene.highlightMaterial.edges = false;\n // scene.highlightMaterial.edgeColor = [0, 0.6, 1];\n // scene.highlightMaterial.edgeAlpha = 0.9;\n // scene.highlightMaterial.fill = true;\n scene.highlightMaterial.fillAlpha = 0.1;\n scene.highlightMaterial.fillColor = [0.6, 0.7, 0.8];\n //------------------------------------------------------------------------------------------------------------------\n // Configure points material\n //------------------------------------------------------------------------------------------------------------------\n scene.pointsMaterial.pointSize = 1;\n scene.pointsMaterial.roundPoints = true;\n scene.pointsMaterial.perspectivePoints = true;\n scene.pointsMaterial.minPerspectivePointSize = 2;\n scene.pointsMaterial.maxPerspectivePointSize = 4;\n // Camera control\n this.viewer.cameraControl.panRightClick = true;\n this.viewer.cameraControl.followPointer = true;\n this.viewer.cameraControl.doublePickFlyTo = false;\n this.viewer.cameraControl.smartPivot = true;\n // Dolly tweaks for best precision when aligning camera for BCF snapshots\n this.viewer.cameraControl.keyboardDollyRate = 100.0;\n this.viewer.cameraControl.mouseWheelDollyRate = 100.0;\n this.viewer.cameraControl.dollyInertia = 0;\n this.viewer.cameraControl.dollyMinSpeed = 0.04;\n this.viewer.cameraControl.dollyProximityThreshold = 30.0;\n const cameraPivotElement = document\n .createRange()\n .createContextualFragment(\"<div class='tctwins-camera-pivot-marker'></div>\").firstChild;\n this.viewer.scene.canvas.canvas.parentNode.appendChild(cameraPivotElement);\n this.viewer.cameraControl.pivotElement = cameraPivotElement;\n scene.camera.perspective.near = 0.01;\n scene.camera.perspective.far = 3000.0;\n scene.camera.ortho.near = 0.01;\n scene.camera.ortho.far = 2000.0; //\n // Scalable Ambient Obscurance (SAO) defaults\n // Since SAO is non-interactive, set to higher-quality\n const { sao } = scene;\n sao.enabled = false;\n sao.numSamples = 50;\n sao.kernelRadius = 200;\n }\n _initConfigs() {\n this.setConfigs({\n cameraNear: \"0.05\",\n cameraFar: \"3000.0\",\n smartPivot: true,\n saoEnabled: false,\n pbrEnabled: true,\n saoBias: \"0.5\",\n saoIntensity: \"0.15\",\n saoNumSamples: \"40\",\n saoKernelRadius: \"100\",\n edgesEnabled: false,\n xrayContext: true,\n xrayPickable: true,\n selectedGlowThrough: true,\n highlightGlowThrough: true,\n backgroundTransparency: true,\n backgroundColor: [1, 1.0, 1.0],\n objectColorSource: \"model\",\n externalMetadata: false,\n dtxEnabled: true,\n snapRadius: 20\n });\n }\n /**\n * Sets a batch of viewer configurations.\n *\n * Note that this method is not to be confused with {@link BIMViewer#setViewerState}, which batch-updates various states of the viewer's UI and 3D view.\n *\n * See [Viewer Configurations] for the list of available configurations.\n *\n * @param {*} viewerConfigs Map of key-value configuration pairs.\n */\n setConfigs(viewerConfigs) {\n for (const name in viewerConfigs) {\n if (Object.prototype.hasOwnProperty.call(viewerConfigs, name)) {\n const value = viewerConfigs[name];\n this.setConfig(name, value);\n }\n }\n // viewerConfigs.forEach((name: string) => {\n // if (Object.prototype.hasOwnProperty.call(viewerConfigs, name)) {\n // const value = viewerConfigs[name];\n // this.setConfig(name, value);\n // }\n // });\n }\n /**\n * Sets a viewer configuration.\n *\n * See [Viewer Configurations] for the list of available configurations.\n *\n * @param {String} name Configuration name.\n * @param {*} value Configuration value.\n */\n setConfig(name, value) {\n function parseBool(value) {\n return value === true || value === \"true\";\n }\n try {\n switch (name) {\n case \"backgroundTransparency\":\n const transparent = value;\n this.setBackgroundTransparent(transparent);\n this._configs[name] = transparent;\n break;\n case \"backgroundColor\":\n if (this._configs.backgroundTransparency) {\n break;\n }\n const rgbColor = value;\n this.setBackgroundColor(rgbColor);\n this._configs[name] = rgbColor;\n break;\n case \"cameraNear\":\n const near = parseFloat(value);\n this.viewer.scene.camera.perspective.near = near;\n this.viewer.scene.camera.ortho.near = near;\n this._configs[name] = near;\n break;\n case \"cameraFar\":\n const far = parseFloat(value);\n this.viewer.scene.camera.perspective.far = far;\n // this.viewer.scene.camera.ortho.far = far;\n this._configs[name] = far;\n break;\n case \"smartPivot\":\n this.viewer.cameraControl.smartPivot = this._configs[name] = parseBool(value);\n break;\n case \"saoEnabled\":\n // todo:\n this.viewer.scene.saoEnabled = this._configs[name] = parseBool(value);\n break;\n case \"saoBias\":\n this.viewer.scene.sao.bias = parseFloat(value);\n break;\n case \"saoIntensity\":\n this.viewer.scene.sao.intensity = parseFloat(value);\n break;\n case \"saoKernelRadius\":\n this.viewer.scene.sao.kernelRadius = this._configs[name] = parseFloat(value);\n break;\n case \"saoNumSamples\":\n this.viewer.scene.sao.numSamples = this._configs[name] = parseFloat(value);\n break;\n case \"saoBlur\":\n this.viewer.scene.sao.blur = this._configs[name] = parseBool(value);\n break;\n case \"edgesEnabled\":\n this.setEdgesEnabled(value);\n break;\n case \"pbrEnabled\":\n // this.viewer.scene.pbrEnabled = this._configs[name] = parseBool(value);\n break;\n case \"viewFitFOV\":\n this.viewer.cameraFlight.fitFOV = this._configs[name] = parseFloat(value);\n break;\n case \"viewFitDuration\":\n this.viewer.cameraFlight.duration = this._configs[name] = parseFloat(value);\n break;\n case \"perspectiveFOV\":\n this.viewer.camera.perspective.fov = this._configs[name] = parseFloat(value);\n break;\n case \"excludeUnclassifiedObjects\":\n this._configs[name] = parseBool(value);\n break;\n case \"objectColorSource\":\n this.setObjectColorSource(value);\n this._configs[name] = value;\n break;\n case \"xrayContext\":\n this._configs[name] = value;\n break;\n case \"xrayPickable\":\n this._configs[name] = parseBool(value);\n break;\n case \"selectedGlowThrough\":\n const selectedGlowThrough = (this._configs[name] = parseBool(value));\n const { selectedMaterial } = this.viewer.scene;\n selectedMaterial.glowThrough = selectedGlowThrough;\n selectedMaterial.fillAlpha = selectedGlowThrough ? 0.5 : 1.0;\n selectedMaterial.edgeAlpha = selectedGlowThrough ? 0.5 : 1.0;\n break;\n case \"highlightGlowThrough\":\n const highlightGlowThrough = (this._configs[name] = parseBool(value));\n const { highlightMaterial } = this.viewer.scene;\n highlightMaterial.glowThrough = highlightGlowThrough;\n highlightMaterial.fillAlpha = highlightGlowThrough ? 0.1 : 1.0;\n highlightMaterial.edgeAlpha = highlightGlowThrough ? 0.1 : 1.0;\n break;\n case \"externalMetadata\":\n this._configs[name] = value;\n break;\n case \"showSpaces\":\n // this._configs[name] = parseBool(value);\n this._showSpacesMode.setActive(value);\n break;\n case \"dtxEnabled\":\n this._configs[name] = parseBool(value);\n this.viewer.scene.dtxEnabled = value;\n break;\n case \"snapRadius\":\n this.setSnapRadius(value);\n break;\n default:\n this.error(`setConfig() - unsupported configuration: '${name}'`);\n }\n }\n catch (e) {\n this.error(`setConfig() - failed to configure ${name}: ${e}`);\n }\n }\n /**\n * Gets the value of a viewer configuration.\n *\n * These are set with {@link BIMViewer#setConfig} and {@link BIMViewer#setConfigs}.\n *\n * @param {String} name Configuration name.\n * @ereturns {*} Configuration value.\n */\n getConfig(name) {\n return this._configs[name];\n }\n getConfigs() {\n return this._configs;\n }\n //------------------------------------------------------------------------------------------------------------------\n // 查询\n //------------------------------------------------------------------------------------------------------------------\n /**\n * Returns the IDs of the models in the currently loaded project.\n *\n * @returns {String[]} The IDs of the models in the currently loaded project.\n */\n modelId() {\n return this._modelId;\n }\n /**\n * Loads a model into the viewer.\n *\n * Assumes that the project containing the model is currently loaded.\n *\n * @param {String} modelId ID of the model to load. Must be the ID of one of the models in the currently loaded project.\n * @param {Function} done Callback invoked on success.\n * @param {Function} error Callback invoked on failure, into which the error message string is passed.\n */\n loadModel(done, error) {\n if (!done)\n done = () => { };\n if (!error)\n error = () => { };\n this._modelsExplorer.loadModel(this._modelId, () => {\n done();\n }, (errorMsg) => {\n // this.error(`loadModel() - ${errorMsg}`);\n error(errorMsg);\n });\n }\n /**\n * 单独加载元数据\n * @param deflatedMetadata\n */\n loadMetadata(deflatedMetadata, force = true, done) {\n this._modelsExplorer.loadMetadata(this.viewer.metaScene.metaModels[this._modelId], deflatedMetadata, force, () => {\n this._metaLoaded = true;\n if (this._focusPartial) {\n this.viewFitPartial(0, done);\n }\n else {\n done;\n }\n });\n }\n /**\n * Sets where the colors for model objects will be loaded from.\n *\n * Options are:\n *\n * * \"model\" - (default) load colors from models, and\n * * \"viewer\" - load colors from the viewer's inbuilt table of colors for IFC types.\n *\n * This is \"model\" by default.\n *\n * @param {String} source Where colors will be loaded from - \"model\" or \"viewer\".\n */\n setObjectColorSource(source) {\n switch (source) {\n case \"model\":\n break;\n case \"viewer\":\n break;\n default:\n source = \"model\";\n this.error(\"setObjectColorSource() - Unsupported value - accepted values are 'model' and 'viewer' - defaulting to 'model'\");\n return;\n }\n this._objectColorSource = source;\n }\n /**\n * 获取构件属性\n * @param objectId\n * @returns\n */\n getObjectProperties(objectId) {\n const metaObject = this.viewer.metaScene.metaObjects[objectId];\n if (!metaObject) {\n return null;\n }\n const info = {\n id: metaObject.id,\n name: metaObject.name,\n type: metaObject.type,\n propertySets: []\n };\n const { propertySets } = metaObject;\n if (propertySets && propertySets.length > 0) {\n for (let i = 0; i < propertySets.length; i++) {\n const properties = propertySets[i].properties;\n const propertyList = [];\n for (let j = 0; j < properties.length; j++) {\n const properValue = {};\n properValue[properties[j].name] = properties[j].value;\n propertyList.push(properValue);\n }\n const propertyset = {\n id: propertySets[i].id,\n name: propertySets[i].name,\n properties: propertyList,\n type: propertySets[i].type\n };\n info.propertySets.push(propertyset);\n }\n }\n return info;\n }\n /**\n * 获取模型信息\n * @returns\n */\n getModelInfo() {\n const metaModel = this.viewer.metaScene.metaModels[this._modelId];\n const modelInfo = {\n id: metaModel.id,\n createDate: metaModel.createdAt ? metaModel.createdAt : \"\",\n author: metaModel.author ? metaModel.author : \"\",\n objectCount: metaModel.objectCount ? metaModel.objectCount : \"\",\n propertySetCount: metaModel.propertySetCount ? metaModel.propertySetCount : \"\"\n };\n return modelInfo;\n }\n //------------------------------------------------------------------------------------------------------------------\n // 视图设置\n //------------------------------------------------------------------------------------------------------------------\n /**\n * Sets whether or not the given objects are visible.\n *\n * @param {String[]} objectIds IDs of objects.\n * @param {Boolean} visible True to set objects visible, false to set them invisible.\n */\n setObjectsVisible(objectIds, visible) {\n this._withObjectsInSubtree(objectIds, (entity) => {\n entity.visible = visible;\n });\n }\n /**\n * Sets whether or not the given objects are selected.\n *\n * @param {String[]} objectIds IDs of objects.\n * @param {Boolean} selected Whether or not to set the objects selected.\n */\n setObjectsSelected(objectIds, selected) {\n this._withObjectsInSubtree(objectIds, (entity) => {\n entity.selected = selected;\n });\n }\n /**\n * Sets whether or not the given objects are X-rayed.\n *\n * @param {String[]} objectIds IDs of objects.\n * @param {Boolean} xrayed Whether or not to X-ray the objects.\n */\n setObjectsXRayed(objectIds, xrayed) {\n this._withObjectsInSubtree(objectIds, (entity) => {\n entity.xrayed = xrayed;\n });\n }\n _withObjectsInSubtree(objectIds, callback) {\n if (!objectIds) {\n this.error(\"Argument expected: objectIds\");\n return;\n }\n objectIds.forEach((objectId) => {\n // const objectId = objectIds[index];\n this.viewer.metaScene.withMetaObjectsInSubtree(objectId, (metaObject) => {\n const entity = this.viewer.scene.objects[metaObject.id];\n if (entity) {\n callback(entity);\n }\n });\n });\n }\n /**\n * Flies the camera to fit the given object in view.\n *\n * @param {String} objectId ID of the object\n * @param {Function} done Callback invoked on completion\n */\n flyToObject(objectId, done) {\n if (!objectId) {\n this.error(\"flyToObject() - Argument expected: objectId\");\n return;\n }\n const { viewer } = this;\n const { scene } = viewer;\n const objectIds = [];\n this.viewer.metaScene.withMetaObjectsInSubtree(objectId, (metaObject) => {\n if (scene.objects[metaObject.id]) {\n objectIds.push(metaObject.id);\n }\n });\n if (objectIds.length === 0) {\n this.error(`Object not found in viewer: '${objectId}'`);\n if (done) {\n done();\n }\n return;\n }\n scene.setObjectsVisible(objectIds, true);\n scene.setObjectsHighlighted(objectIds, true);\n const aabb = scene.getAABB(objectIds);\n viewer.cameraFlight.flyTo({\n aabb\n }, () => {\n if (done) {\n done();\n }\n setTimeout(() => {\n scene.setObjectsHighlighted(scene.highlightedObjectIds, false);\n }, 500);\n });\n viewer.cameraControl.pivotPos = _xtctwins_tctwins_core__WEBPACK_IMPORTED_MODULE_0__.math.getAABB3Center(aabb);\n }\n /**\n * Flies the camera to fit the given objects in view.\n *\n * @param {String[]} objectIds IDs of the objects\n * @param {Function} done Callback invoked on completion\n */\n viewFitObjects(objectIds, done) {\n if (!objectIds) {\n this.error(\"flyToObject() - Argument expected: objectIds\");\n return;\n }\n const { viewer } = this;\n const { scene } = viewer;\n const entityIds = [];\n objectIds.forEach((objectId) => {\n this.viewer.metaScene.withMetaObjectsInSubtree(objectId, (metaObject) => {\n if (scene.objects[metaObject.id]) {\n entityIds.push(metaObject.id);\n }\n });\n });\n if (entityIds.length === 0) {\n if (done) {\n done();\n }\n return;\n }\n scene.setObjectsVisible(entityIds, true);\n scene.setObjectsHighlighted(entityIds, true);\n const aabb = scene.getAABB(entityIds);\n viewer.cameraFlight.flyTo({\n aabb\n }, () => {\n if (done) {\n done();\n }\n setTimeout(() => {\n scene.setObjectsHighlighted(scene.highlightedObjectIds, false);\n }, 500);\n });\n viewer.cameraControl.pivotPos = _xtctwins_tctwins_core__WEBPACK_IMPORTED_MODULE_0__.math.getAABB3Center(aabb);\n }\n /**\n * 相机立刻聚焦到指定构建id的对象,没有转移视角动画\n * @param {String} objectId\n */\n jumpToObjects(objectIds) {\n if (!objectIds) {\n this.error(\"jumpToObject() - Argument expected: objectIds\");\n return;\n }\n const { viewer } = this;\n const { scene } = viewer;\n const entityIds = [];\n this.viewer.metaScene.withMetaObjectsInSubtree(objectIds, (metaObject) => {\n if (scene.objects[metaObject.id]) {\n entityIds.push(metaObject.id);\n }\n });\n if (entityIds.length === 0) {\n this.error(`Objects not found in viewer: '${objectIds}'`);\n return;\n }\n scene.setObjectsVisible(entityIds, true);\n const aabb = scene.getAABB(entityIds);\n viewer.cameraFlight.jumpTo({\n aabb\n });\n viewer.cameraControl.pivotPos = _xtctwins_tctwins_core__WEBPACK_IMPORTED_MODULE_0__.math.getAABB3Center(aabb);\n }\n /**\n * 设置相机位置\n * @param {Number[]} [params.eye] Eye position.\n * @param {Number[]} [params.look] Point of interest.\n * @param {Number[]} [params.up] Direction of \"up\".\n */\n setCamera(params) {\n const { viewer } = this;\n const { scene } = viewer;\n const { camera } = scene;\n if (params.eye) {\n camera.eye = params.eye;\n }\n if (params.look) {\n camera.look = params.look;\n }\n if (params.up) {\n camera.up = params.up;\n }\n }\n /**\n * 相机移动到指定视角\n * @param {Number[]} [params.eye] 相机位置.\n * @param {Number[]} [params.look] 相机视点\n * @param {Number[]} [params.up] 上方方向\n */\n flyToNewView(params) {\n this.viewer.cameraControl.pivotPos = params.look;\n this.viewer.cameraFlight.flyTo({\n look: params.look,\n eye: params.eye,\n up: params.up,\n duration: params.duration\n });\n }\n /**\n * Fits the given models in view.\n *\n * @param {String[]} modelIds ID of the models.\n * @param {Function} [done] Callback invoked on completion. Will be animated if this is given, otherwise will be instantaneous.\n */\n viewFitModels(modelIds, done) {\n if (!modelIds) {\n this.error(\"viewFitModels() - Argument expected: modelIds\");\n return;\n }\n const { viewer } = this;\n const { scene } = viewer;\n const aabb = _xtctwins_tctwins_core__WEBPACK_IMPORTED_MODULE_0__.math.AABB3();\n _xtctwins_tctwins_core__WEBPACK_IMPORTED_MODULE_0__.math.collapseAABB3(aabb);\n modelIds.forEach((modelId) => {\n const model = scene.models[modelId];\n if (model) {\n model.visible = true;\n model.highlighted = true;\n _xtctwins_tctwins_core__WEBPACK_IMPORTED_MODULE_0__.math.expandAABB3(aabb, model.aabb);\n }\n else {\n this.error(`Model not found in viewer: '${modelId}'`);\n }\n });\n if (done) {\n viewer.cameraFlight.flyTo({\n aabb\n }, () => {\n done();\n setTimeout(() => {\n scene.setObjectsHighlighted(scene.highlightedObjectIds, false);\n }, 500);\n });\n }\n else {\n viewer.cameraFlight.jumpTo({\n aabb\n });\n setTimeout(() => {\n scene.setObjectsHighlighted(scene.highlightedObjectIds, false);\n }, 500);\n }\n viewer.cameraControl.pivotPos = _xtctwins_tctwins_core__WEBPACK_IMPORTED_MODULE_0__.math.getAABB3Center(aabb);\n }\n /**\n * 切换模型分布 - 根据构建检测结果的模型分布情况聚焦不同分布区域\n *\n * 使用:\n * bimViewer.viewFitPartial(1, (partNum:number)=>{\n * console.log(partNum); //当前聚焦的模型分布索引\n * })\n *\n * bimViewer.viewFitPartial((partNum:number)=>{\n * console.log(partNum); //当前聚焦的模型分布索引\n * })\n *\n * bimViewer.viewFitPartial(1); //无回调方法。自动切换分布视角\n *\n * bimViewer.viewFitPartial(); //无指定索引输入,无回调方法。自动切换分布视角\n *\n *\n * @param {number} part - 模型分布索引(例如:根据检测结果,当前模型有三块模型分布,则可以输入[0-2]区间的数字)\n * @param {Function} done -\n */\n viewFitPartial(part, done) {\n let partNum;\n if (typeof part === \"function\") {\n done = part;\n partNum = this._partialFocusIndex += 1;\n }\n else {\n partNum = part !== null && part !== void 0 ? part : (this._partialFocusIndex += 1);\n }\n if (partNum >= 0 && partNum < this._partialObjectIds.length) {\n this.viewFitObjects(this._partialObjectIds[partNum], () => {\n for (let i = 0; i < this._partialObjectIds.length; i++) {\n if (partNum == i)\n this.setObjectsVisible(this._partialObjectIds[i], true);\n else\n this.setObjectsVisible(this._partialObjectIds[i], false);\n }\n done ? done(partNum) : done;\n });\n }\n else {\n partNum = this._partialFocusIndex = 0;\n this.viewFitObjects(this._partialObjectIds[partNum], () => {\n for (let i = 0; i < this._partialObjectIds.length; i++) {\n if (partNum == i)\n this.setObjectsVisible(this._partialObjectIds[i], true);\n else\n this.setObjectsVisible(this._partialObjectIds[i], false);\n }\n done ? done(partNum) : done;\n });\n }\n }\n /**\n * 设置模型分布 - 根据构建检测结果设置不同分布位置的模型构建ID数组\n * @param {string[][]} partialObjectIds\n */\n setPartialObjectIds(partialObjectIds) {\n const newPartialIdsList = [];\n for (let i = 0; i < partialObjectIds.length; i++) {\n newPartialIdsList.push(partialObjectIds[i]);\n }\n this._partialObjectIds = newPartialIdsList;\n this.viewer.cameraControl.smartPivot = false;\n this.navCubeMode.fitVisible = true;\n this._focusPartial = true;\n if (this._metaLoaded)\n this.viewFitPartial(0);\n }\n /// /////////部分操作////////////////////////////////////////\n /**\n * Transitions the viewer into an isolated view of the given building storey.\n *\n * Does nothing and logs an error if no object of the given ID is in the viewer, or if the object is not an ````IfcBuildingStorey````.\n *\n * @param {String} storeyObjectId ID of an ````IfcBuildingStorey```` object.\n * @param {Function} [done] Optional callback to invoke on completion. When provided, the transition will be animated, with the camera flying into position. Otherwise, the transition will be instant, with the camera jumping into position.\n */\n selectStorey(storeyObjectId, done = () => { }) {\n const { metaScene } = this.viewer;\n const storeyMetaObject = metaScene.metaObjects[storeyObjectId];\n if (!storeyMetaObject) {\n this.error(`selectStorey() - Object is not found: '${storeyObjectId}'`);\n return;\n }\n if (storeyMetaObject.type !== \"IfcBuildingStorey\") {\n this.error(`selectStorey() - Object is not an IfcBuildingStorey: '${storeyObjectId}'`);\n return;\n }\n this._storeysExplorer.selectStorey(storeyObjectId, done);\n }\n /**\n * Sets whether or not keyboard camera control is enabled.\n *\n * This is useful when we don't want key events over the canvas to clash with other UI elements outside the canvas.\n *\n * Default value is ````true````.\n *\n * @param {Boolean} enabled Set ````true```` to enable keyboard input.\n */\n setKeyboardEnabled(enabled) {\n this.viewer.scene.input.keyboardEnabled = enabled;\n }\n /**\n * Gets whether keyboard camera control is enabled.\n *\n * This is useful when we don't want key events over the canvas to clash with other UI elements outside the canvas.\n *\n * Default value is ````true````.\n *\n * @returns {Boolean} Returns ````true```` if keyboard input is enabled.\n */\n getKeyboardEnabled() {\n return this.viewer.scene.input.keyboardEnabled;\n }\n /**\n * 缓冲对象spinner显隐设置\n * @param show\n */\n showSpinner(show = !this.viewer.scene.canvas.spinner.visible) {\n this.viewer.scene.canvas.spinner.visible = show;\n }\n /**\n * 更新包围盒 - 排除异常构建并更新包围盒\n * @param exceptionIDs - 异常构建ID\n * @param callback - 回调\n */\n updateAABB(exceptionIDs, callback) {\n if (exceptionIDs.length > 0) {\n this._hasOutlier = true;\n this._outlierObjectIds = exceptionIDs;\n }\n const model = this.viewer.scene.models[this._modelId];\n const newExceptionsIds = exceptionIDs.concat(model.exceptionIds);\n model.exceptionIds = newExceptionsIds;\n this.viewer.scene.setObjectsVisible(newExceptionsIds, false);\n this.viewer.scene.on(\"aabb\", () => {\n if (typeof callback === \"function\")\n callback();\n });\n }\n /**\n * 销毁\n */\n destroy(callback) {\n var _a;\n this.measureDistanceTool.destroy();\n this.measureAngleTool.destroy();\n this._annotationTool.destroy();\n this._commentsTool.destroy();\n this._bcfViewpointsPlugin.destroy();\n this._modelsExplorer.destroy();\n this._classesExplorer.destroy();\n this._objectsExplorer.destroy();\n this._storeysExplorer.destroy();\n this._eventTrigger.destroy();\n const dos = document.querySelector(\".tctwins-camera-pivot-marker\");\n if (dos) {\n (_a = dos.parentNode) === null || _a === void 0 ? void 0 : _a.removeChild(dos);\n }\n this.viewer.destroy(callback);\n }\n /// /////////右键菜单////////////////////////////////////////\n // 选中\n /**\n * 设置对象被选中与否\n * @param entity\n * @param selected\n */\n setEntitySelected(entity, selected = !entity.selected) {\n entity.selected = selected;\n }\n /**\n * 选中其他对象\n * @param entity\n */\n setOthersSelected(entity) {\n this.setAllObjectsSelected(true);\n this.setEntitySelected(entity, true);\n }\n /**\n * 设置全部选中与否\n * @param {Boolean} selected\n */\n setAllObjectsSelected(selected) {\n if (selected) {\n this.viewer.scene.setObjectsSelected(this.viewer.scene.objectIds, true);\n }\n else {\n this.viewer.scene.setObjectsSelected(this.viewer.scene.selectedObjectIds, false);\n }\n }\n // 聚焦\n /**\n * 设置相机适应选中对象\n * @param entity\n */\n viewFitEntity(entity) {\n const { scene } = this.viewer;\n this.viewer.cameraFlight.flyTo({\n aabb: entity.aabb,\n duration: 0.5\n }, () => {\n setTimeout(() => {\n scene.setObjectsHighlighted(scene.highlightedObjectIds, false);\n }, 500);\n });\n this.viewer.cameraControl.pivotPos = _xtctwins_tctwins_core__WEBPACK_IMPORTED_MODULE_0__.math.getAABB3Center(entity.aabb);\n }\n /**\n * 相机适应所有选中对象\n */\n viewFitSelectedObjects() {\n this.viewFitObjects(this.viewer.scene.highlightedObjectIds, () => { });\n }\n /**\n * Flies the camera to fit all objects in view.\n *\n * @param {Function} done Callback invoked on completion\n */\n viewFitAll(done) {\n if (this._focusPartial) {\n this.viewFitPartial(this._partialFocusIndex, done);\n return;\n }\n this._fitAction.fit(done);\n }\n // 隐藏\n /**\n * 设置选中对象隐藏与否\n * @param entity\n */\n setEntityHide(entity, visible = !entity.visible) {\n entity.visible = visible;\n }\n /**\n * 隐藏选中对象以外的其他模型对象\n * @param entity\n * @returns\n */\n setOthersHide(entity) {\n const metaObject = this.viewer.metaScene.metaObjects[entity.id];\n if (!metaObject) {\n return;\n }\n this.viewer.scene.setObjectsVisible(this.viewer.scene.visibleObjectIds, false);\n metaObject.withMetaObjectsInSubtree((metaObject) => {\n const entity = this.viewer.scene.objects[metaObject.id];\n if (entity) {\n entity.visible = true;\n }\n });\n }\n /**\n * 显示所有对象\n * @param {Boolean} visible True to set objects visible, false to set them invisible.\n */\n setAllObjectsVisible(visible) {\n if (visible) {\n this.viewer.scene.setObjectsVisible(this.viewer.scene.objectIds, true);\n if (this._hasOutlier)\n this.viewer.scene.setObjectsVisible(this._outlierObjectIds, false);\n }\n else {\n this.viewer.scene.setObjectsVisible(this.viewer.scene.visibleObjectIds, false);\n }\n }\n // 透视\n /**\n * 设置选中对象透视与否\n * @param entity\n * @param xrayed\n */\n setEntityXRayed(entity, xrayed = !entity.xrayed) {\n entity.xrayed = xrayed;\n entity.pickable = this.getConfig(\"xrayPickable\");\n }\n /**\n * 设置其他对象透视\n * @param entity\n * @returns\n */\n setOthersXRayed(entity) {\n const { scene } = this.viewer;\n const metaObject = this.viewer.metaScene.metaObjects[entity.id];\n if (!metaObject) {\n return;\n }\n scene.setObjectsVisible(scene.objectIds, true);\n scene.setObjectsXRayed(scene.objectIds, true);\n if (!this.getConfig(\"xrayPickable\")) {\n scene.setObjectsPickable(scene.objectIds, false);\n }\n metaObject.withMetaObjectsInSubtree((metaObject) => {\n const entity = scene.objects[metaObject.id];\n if (entity) {\n entity.xrayed = false;\n entity.pickable = true;\n }\n });\n }\n /**\n * 设置所有对象透视与否\n * @param {Boolean} xrayed Whether or not to set all objects X-rayed.\n */\n setAllObjectsXRayed(xrayed) {\n if (xrayed) {\n this.viewer.scene.setObjectsXRayed(this.viewer.scene.objectIds, true);\n }\n else {\n this.viewer.scene.setObjectsXRayed(this.viewer.scene.xrayedObjectIds, false);\n }\n }\n // 判断\n entityVisble(entity) {\n return entity.visible;\n }\n entityXRayed(entity) {\n return entity.xrayed;\n }\n entityChosed(entity) {\n return entity.selected;\n }\n /**\n * 判断是否有被隐藏的\n * @returns\n */\n hiddenMoreThanOne() {\n return this.viewer.scene.numObjects - this.viewer.scene.numVisibleObjects > 0;\n }\n /**\n * 判断是否有被透视的\n * @returns\n */\n xRayedMoreThanOne() {\n return this.viewer.scene.numXRayedObjects > 0;\n }\n /**\n * 判断是否有被选中的\n * @returns\n */\n SelectedMoreThanOne() {\n return this.viewer.scene.numSelectedObjects > 0;\n }\n /// /////////设置背景颜色,透明,边缘等 初始设置///////////////////////////\n /**\n * Sets the viewer's background color.\n *\n * @param {boolean}\n */\n setBackgroundTransparent(trans = !this.viewer.scene.backgroundTransparent) {\n this.viewer.scene.backgroundTransparent = trans;\n this.viewer.scene.render(true);\n }\n /**\n * Sets the viewer's background color.\n *\n * @param {Number[]} rgbColor Three-element array of RGB values, each in range ````[0..1]````.\n */\n setBackgroundColor(rgbColor) {\n this.viewer.scene.backgroundColor = rgbColor;\n this.viewer.scene.render(true);\n }\n /**\n * 设置导航盒尺寸\n * @param {number} size 默认是200\n */\n setNavCubeSize(size) {\n this.navCubeCanvasElement.style.width = `${size.toString()}px`;\n this.navCubeCanvasElement.style.height = `${size.toString()}px`;\n }\n /**\n * 设置导航盒的位置\n * @param {string} direction e.g.\"left\",\"right\",\"top\",\"bottom\"\n * @param {number} pos\n */\n setNavCubePosition(direction, pos) {\n switch (direction) {\n case \"top\":\n this.navCubeCanvasElement.style.top = `${pos.toString()}px`;\n this.navCubeCanvasElement.style.bottom = \"\";\n break;\n case \"bottom\":\n this.navCubeCanvasElement.style.top = \"\";\n this.navCubeCanvasElement.style.bottom = `${pos.toString()}px`;\n break;\n case \"right\":\n this.navCubeCanvasElement.style.left = \"\";\n this.navCubeCanvasElement.style.right = `${pos.toString()}px`;\n break;\n case \"left\":\n this.navCubeCanvasElement.style.right = \"\";\n this.navCubeCanvasElement.style.left = `${pos.toString()}px`;\n break;\n }\n }\n /**\n * 更新canvas\n */\n updateCanvas() {\n this.viewer.scene.canvas.dirtyBoundary = true;\n }\n /**\n * 设置测量鼠标偏移量\n * @param offsetX\n * @param offsetY\n */\n setMeasureOffSet(offsetX, offsetY) {\n this._measureTool.setMeasureOffSet(offsetX, offsetY);\n }\n /**\n * 设置批注鼠标偏移量\n * @param offsetX\n * @param offsetY\n */\n setCommentsOffset(offsetX, offsetY) {\n this._commentsTool.offsetX = offsetX;\n this._commentsTool.offsetY = offsetY;\n }\n /**\n * 设置测量鼠标吸附点灵敏度\n * @param radius\n */\n setSnapRadius(radius) {\n this.measureTool.setSnapRadius(radius);\n }\n /**\n * 设置是否是触屏模式\n * @param {boolean} isTouch\n */\n setIsTouch(isTouch) {\n this.sectionTool.isTouch = isTouch;\n this.commentTool.isTouch = isTouch;\n }\n /**\n * 调整光照强度 0-100\n * @param num\n */\n setLightIntensity(num) {\n if (num < 0 || num > 100)\n return;\n for (let name in this.viewer.scene.lightsObject) {\n this.viewer.scene.lightsObject[name].intensity = 0.63 + (num - 50) / 200;\n }\n }\n /**\n * 设置空间构建的颜色模式;默认 1\n * @param {number} colorState\n */\n setSpaceMaterialColor(colorState) {\n if (colorState === 1)\n this.viewer.scene.highlightMaterial.fillColor = [0.6, 0.7, 0.8];\n else if (colorState === 2)\n this.viewer.scene.highlightMaterial.fillColor = [0.2, 0.3, 0.4];\n }\n /////////////渲染设置//////////////////////\n /**\n * set edges Enable\n * @param {boolean} edgesEnabled\n */\n setEdgesEnabled(edgesEnabled = !this.viewer.scene.edgesEnabled) {\n this.viewer.scene.edgesEnabled = edgesEnabled;\n this.viewer.scene.render(true);\n }\n /**\n * 是否开启环境光\n * @param {boolean} saoEnabled\n */\n setSAOEnabled(saoEnabled = !this.viewer.scene.saoEnabled) {\n this.viewer.scene.saoEnabled = saoEnabled;\n }\n setDTXEnabled(dtxEnabled = !this.viewer.scene.dtxEnabled) {\n this.viewer.scene.dtxEnabled = dtxEnabled;\n }\n setPBREnabled(pbrEnabled = !this.viewer.scene.pbrEnabled) {\n this.viewer.scene.pbrEnabled = pbrEnabled;\n }\n /**\n * 视图复位 - 恢复默认视图\n */\n resetView(callback) {\n if (this._focusPartial) {\n this.setDirection(25);\n return;\n }\n this._resetAction.reset(callback);\n }\n /**\n * 自适应 - 在当前相机视角适应视图填充画面\n */\n fitView(callback) {\n if (this._focusPartial) {\n this.viewFitPartial(this._partialFocusIndex, callback);\n return;\n }\n this._fitAction.fit();\n }\n /**\n * 标注开关\n * @param active\n * @param callback\n */\n SetAnnotationToolActive(active = !this._annotationTool.getActive(), callback) {\n this._annotationTool.setActive(active);\n if (callback)\n callback(this._annotationTool.getActive());\n }\n /**\n * 批注开关\n * @param active\n * @param callback\n */\n SetCommentsToolActive(active = !this._commentsTool.getActive(), callback) {\n this._commentsTool.setActive(active);\n if (callback)\n callback(this._commentsTool.getActive());\n }\n /**\n * 第一人称视角\n * @param active\n * @param callback\n */\n SetFirstPersonModeActive(active = !this._firstPersonMode.getActive(), callback) {\n this._firstPersonMode.setActive(active);\n if (callback)\n callback(this._firstPersonMode.getActive());\n }\n /**\n * 测量工具统一开关\n * @param active\n * @param callback\n */\n SetMeasureToolActive(active = !this.measureAngleTool.getActive(), callback) {\n this._measureTool.setActive(active);\n if (callback)\n callback(this._measureTool.getActive());\n }\n /**\n * 角度测量开关\n * @param active\n * @param callback\n */\n SetMeasureAngleActive(active = !this.measureAngleTool.getActive(), callback) {\n this._measureTool.SetMeasureAngleActive(active);\n if (callback)\n callback(this.measureAngleTool.getActive());\n }\n /**\n * 距离测量开关\n * @param active\n * @param callback\n */\n SetMeasureDistanceActive(active = !this.measureDistanceTool.getActive(), callback) {\n this._measureTool.SetMeasureDistanceActive(active);\n if (callback)\n callback(this.measureDistanceTool.getActive());\n }\n /**\n * 剖切工具开关\n * @param active\n * @param callback\n */\n SetSectionToolActive(active = !this._sectionTool.getActive(), callback) {\n this._sectionTool.setActive(active);\n if (callback)\n callback(this._sectionTool.getActive());\n }\n /**\n * 隐藏工具开关\n * @param active\n * @param callback\n */\n SetHideToolActive(active, callback) {\n this._hideTool.setActive(active);\n if (callback)\n callback();\n }\n /**\n * 框选开关\n * @param active\n * @param callback\n */\n SetMarqueeSelectionActive(active, callback) {\n // this._marqueeSelectionTool.setActive(active);\n if (callback)\n callback();\n }\n /**\n * 相机视角开关\n * @param active\n * @param callback\n */\n SetOrthoModeActive(active = !this._orthoMode.getActive(), callback) {\n this._orthoMode.setActive(active, callback);\n }\n /**\n * 3d/2d视角开关\n * @param active\n * @param callback\n */\n SetThreeDModeActive(active = !this._threeDMode.getActive(), callback) {\n this._threeDMode.setActive(active, callback);\n }\n /**\n * 显示空间功能开关\n * @param active\n * @param callback\n */\n SetShowSpaceModeActive(active = !this._showSpacesMode.getActive(), callback) {\n this._showSpacesMode.setActive(active, callback);\n }\n /// ///////////////功能对象/////////////////////\n /**\n * 漫游\n */\n get firstPersonMode() {\n return this._firstPersonMode;\n }\n /**\n * 测量管理工具\n */\n get measureTool() {\n return this._measureTool;\n }\n /**\n * 角度测量\n */\n get measureAngleTool() {\n return this._measureTool.measureAngleTool;\n }\n /**\n * 距离测量\n */\n get measureDistanceTool() {\n return this._measureTool.measureDistanceTool;\n }\n /**\n * 剖切\n */\n get sectionTool() {\n return this._sectionTool;\n }\n /**\n * 批注\n */\n get commentTool() {\n return this._commentsTool;\n }\n /**\n * 标注\n */\n get annotationTool() {\n return this._annotationTool;\n }\n /**\n * 结构树object(对象)\n */\n get objectsExplorer() {\n return this._objectsExplorer;\n }\n /**\n * 结构树class(类别)\n */\n get classesExplorer() {\n return this._classesExplorer;\n }\n /**\n * 结构树storey(楼层)\n */\n get storeysExplorer() {\n return this._storeysExplorer;\n }\n /**\n * 模型加载器\n */\n get modelsExplorer() {\n return this._modelsExplorer;\n }\n /**\n * 相机视角\n */\n get orthoMode() {\n return this._orthoMode;\n }\n /**\n * 2D/3D\n */\n get threeDMode() {\n return this._threeDMode;\n }\n /**\n * 导航盒控制器对象\n */\n get navCubeMode() {\n return this._navCubeMode;\n }\n /////////////////////导航//////////////////////////\n /**\n * 设置相机方向\n * @param {number} dirNum\n */\n setDirection(dirNum) {\n this._navCubeMode.flyByClick(dirNum);\n }\n /**\n * 单击模型对象\n * @param entity\n */\n singleChoseEntity(entity) {\n // this.showObjectProperties(entity.id.toString()); //显示构建属性\n this.setAllObjectsSelected(false); //所有构件高亮取消\n this.setEntitySelected(entity); //选中构件高亮\n }\n /**\n * 单击点击空白\n */\n singleChosedSpace() {\n this.setAllObjectsSelected(false); //所有构件高亮取消\n }\n /**\n * 双击模型对象\n * @param entity\n */\n doubleChoseEntity(entity) {\n this.viewFitEntity(entity); //聚焦构件\n this.setAllObjectsSelected(false); //所有构件高亮取消\n this.setEntitySelected(entity); //选中构件高亮\n }\n /**\n * 回到正常视图\n */\n choseSpace() {\n this.setAllObjectsSelected(false);\n this.viewFitAll();\n }\n /**\n * 初始预览环周截图\n * @param sizeOrCallback\n * @param done\n * @returns\n */\n getPreShot(sizeOrCallback, done) {\n const cameraEnable = this.cameraEnable;\n cameraEnable(false);\n let size = typeof sizeOrCallback === \"function\" ? 1024 : sizeOrCallback;\n if (typeof sizeOrCallback === \"function\")\n done = sizeOrCallback;\n const orbitYawCamera = this.orbitYawCamera;\n const viewer = this.viewer;\n const canvas = document.createElement(\"canvas\");\n const ctx = canvas.getContext(\"2d\");\n const canvasWidth = size * 15;\n const canvasHeight = size;\n canvas.width = canvasWidth;\n canvas.height = canvasHeight;\n const imagesPromises = Array.from({ length: 15 }, () => processImage);\n function processImage() {\n return __awaiter(this, void 0, void 0, function* () {\n yield orbitYawCamera(-18);\n yield delay(100); // 添加延迟,确保相机完成旋转\n return getshot(size);\n });\n }\n function delay(ms) {\n return new Promise((resolve) => setTimeout(resolve, ms));\n }\n function getshot(size) {\n return __awaiter(this, void 0, void 0, function* () {\n const canvas = viewer.scene.canvas.canvas;\n const tempCanvas = document.createElement(\"canvas\");\n const tempCtx = tempCanvas.getContext(\"2d\");\n if (canvas && tempCtx) {\n tempCanvas.width = size;\n tempCanvas.height = size;\n const scaleX = size / canvas.width;\n const scaleY = size / canvas.height;\n const scale = Math.max(scaleX, scaleY);\n const scaledWidth = canvas.width * scale;\n const scaledHeight = canvas.height * scale;\n const offsetX = (size - scaledWidth) / 2;\n const offsetY = (size - scaledHeight) / 2;\n tempCtx.clearRect(0, 0, size, size);\n tempCtx.fillStyle = \"transparent\"; // 设置透明色\n tempCtx.fillRect(0, 0, size, size);\n tempCtx.drawImage(canvas, 0, 0, canvas.width, canvas.height, offsetX, offsetY, scaledWidth, scaledHeight);\n return new Promise((resolve, reject) => {\n const img = new Image();\n img.onload = () => resolve(img);\n img.onerror = reject;\n img.src = tempCanvas.toDataURL(); // 将 Canvas 转换为 data URL\n });\n }\n else {\n return Promise.reject(new Error(\"Canvas or context not found.\"));\n }\n });\n }\n function handleCanvasResult(download) {\n const imageData = canvas.toDataURL(\"image/png\");\n if (download) {\n const downloadLink = document.createElement(\"a\");\n downloadLink.href = imageData;\n downloadLink.download = \"combined_image.png\";\n downloadLink.click();\n }\n cameraEnable(true);\n if (done)\n done(imageData);\n return imageData;\n }\n (() => __awaiter(this, void 0, void 0, function* () {\n for (let i = 0; i < imagesPromises.length; i++) {\n try {\n const img = (yield imagesPromises[i]());\n if (ctx)\n ctx.drawImage(img, i * size, 0);\n }\n catch (error) {\n cameraEnable(true);\n console.error(\"获取图片内容失败:\", error);\n }\n }\n handleCanvasResult(false);\n }))();\n return \"\";\n }\n /**\n * 设置遮挡截图\n * @param callback\n */\n setShelterCanvas(callback) {\n const canvas = this.viewer.scene.canvas.canvas;\n const canvasImage = this.shot(canvas.width, canvas.height, false);\n const shelterImage = document.createElement(\"img\");\n shelterImage.src = canvasImage;\n shelterImage.style.position = \"absolute\";\n shelterImage.style.top = \"0px\";\n shelterImage.style.left = \"0px\";\n shelterImage.style.right = \"0px\";\n shelterImage.style.bottom = \"0px\";\n canvas.parentNode.appendChild(shelterImage);\n if (typeof callback == \"function\")\n callback(shelterImage);\n }\n}\n\n\n//# sourceURL=webpack://@xtctwins/tctwins-bimx-viewer/./src/BIMXViewer.ts?");
47
+ eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"default\": () => (/* binding */ BIMXViewer)\n/* harmony export */ });\n/* harmony import */ var _xtctwins_tctwins_core__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @xtctwins/tctwins-core */ \"./node_modules/@xtctwins/tctwins-core/dist/tctwins-core.es5.js\");\n/* harmony import */ var _messages__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./messages */ \"./src/messages.ts\");\n/* harmony import */ var _EventTrigger__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./EventTrigger */ \"./src/EventTrigger.ts\");\n/* harmony import */ var _Controller__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./Controller */ \"./src/Controller.ts\");\n/* harmony import */ var _toolbar_ResetAction__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./toolbar/ResetAction */ \"./src/toolbar/ResetAction.ts\");\n/* harmony import */ var _toolbar_FitAction__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ./toolbar/FitAction */ \"./src/toolbar/FitAction.ts\");\n/* harmony import */ var _toolbar_FirstPersonMode__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ./toolbar/FirstPersonMode */ \"./src/toolbar/FirstPersonMode.ts\");\n/* harmony import */ var _toolbar_HideTool__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! ./toolbar/HideTool */ \"./src/toolbar/HideTool.ts\");\n/* harmony import */ var _toolbar_ShowSpacesMode__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! ./toolbar/ShowSpacesMode */ \"./src/toolbar/ShowSpacesMode.ts\");\n/* harmony import */ var _toolbar_SectionTool__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(/*! ./toolbar/SectionTool */ \"./src/toolbar/SectionTool.ts\");\n/* harmony import */ var _toolbar_NavCubeMode__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(/*! ./toolbar/NavCubeMode */ \"./src/toolbar/NavCubeMode.ts\");\n/* harmony import */ var _explorer_ModelsExplorer__WEBPACK_IMPORTED_MODULE_11__ = __webpack_require__(/*! ./explorer/ModelsExplorer */ \"./src/explorer/ModelsExplorer.ts\");\n/* harmony import */ var _explorer_ObjectsExplorer__WEBPACK_IMPORTED_MODULE_12__ = __webpack_require__(/*! ./explorer/ObjectsExplorer */ \"./src/explorer/ObjectsExplorer.ts\");\n/* harmony import */ var _explorer_ClassesExplorer__WEBPACK_IMPORTED_MODULE_13__ = __webpack_require__(/*! ./explorer/ClassesExplorer */ \"./src/explorer/ClassesExplorer.ts\");\n/* harmony import */ var _explorer_StoreysExplorer__WEBPACK_IMPORTED_MODULE_14__ = __webpack_require__(/*! ./explorer/StoreysExplorer */ \"./src/explorer/StoreysExplorer.ts\");\n/* harmony import */ var _toolbar_ThreeDMode__WEBPACK_IMPORTED_MODULE_15__ = __webpack_require__(/*! ./toolbar/ThreeDMode */ \"./src/toolbar/ThreeDMode.ts\");\n/* harmony import */ var _toolbar_OrthoMode__WEBPACK_IMPORTED_MODULE_16__ = __webpack_require__(/*! ./toolbar/OrthoMode */ \"./src/toolbar/OrthoMode.ts\");\n/* harmony import */ var _collision_ObjectsKdTree3__WEBPACK_IMPORTED_MODULE_17__ = __webpack_require__(/*! ./collision/ObjectsKdTree3 */ \"./src/collision/ObjectsKdTree3.ts\");\n/* harmony import */ var _toolbar_AnnotationTool__WEBPACK_IMPORTED_MODULE_18__ = __webpack_require__(/*! ./toolbar/AnnotationTool */ \"./src/toolbar/AnnotationTool.ts\");\n/* harmony import */ var _toolbar_MeasureTool__WEBPACK_IMPORTED_MODULE_19__ = __webpack_require__(/*! ./toolbar/MeasureTool */ \"./src/toolbar/MeasureTool.ts\");\n/* harmony import */ var _toolbar_CommentsTool__WEBPACK_IMPORTED_MODULE_20__ = __webpack_require__(/*! ./toolbar/CommentsTool */ \"./src/toolbar/CommentsTool.ts\");\n/* harmony import */ var _server_Server__WEBPACK_IMPORTED_MODULE_21__ = __webpack_require__(/*! ./server/Server */ \"./src/server/Server.ts\");\nvar __awaiter = (undefined && undefined.__awaiter) || function (thisArg, _arguments, P, generator) {\n function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }\n return new (P || (P = Promise))(function (resolve, reject) {\n function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }\n function rejected(value) { try { step(generator[\"throw\"](value)); } catch (e) { reject(e); } }\n function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }\n step((generator = generator.apply(thisArg, _arguments || [])).next());\n });\n};\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n/**\n * 核心模型视图窗口\n * @type {BIMViewer}\n */\nclass BIMXViewer extends _Controller__WEBPACK_IMPORTED_MODULE_3__[\"default\"] {\n /**\n * Constructs a BIMViewer.\n * @param {Server} server Data access strategy.\n * @param {*} cfg Configuration.\n * @param {Boolean} [cfg.enableEditModels=false] Set ````true```` to show \"Add\", \"Edit\" and \"Delete\" options in the Models tab's context menu.\n * @param {Boolean} [cfg.keyboardEventsElement] Optional reference to HTML element on which key events should be handled. Defaults to the HTML Document.\n */\n constructor(cfg = {}) {\n if (!cfg.canvasElement) {\n throw new Error(\"Config expected: canvasElement\");\n }\n if (!cfg.navCubeCanvasElement) {\n throw new Error(\"Config expected: navCubeCanvasElement\");\n }\n const { canvasElement } = cfg;\n const { viewerElement } = cfg;\n const localeService = new _xtctwins_tctwins_core__WEBPACK_IMPORTED_MODULE_0__.LocaleService({\n messages: _messages__WEBPACK_IMPORTED_MODULE_1__[\"default\"],\n locale: \"ch\"\n });\n const viewer = new _xtctwins_tctwins_core__WEBPACK_IMPORTED_MODULE_0__.Viewer({\n passes: 5,\n localeService,\n canvasElement,\n viewerElement,\n transparent: true,\n alphaDepthMask: true,\n backgroundColorFromAmbientLight: true,\n snapRadius: cfg.snapRadius,\n antialias: true,\n saoEnabled: false,\n pbrEnabled: true,\n dtxEnabled: true,\n edgesEnabled: true,\n colorTextureEnabled: true,\n premultipliedAlpha: true,\n resolutionScale: window.devicePixelRatio,\n spinnerElementId: \"engine_spinner\"\n });\n const server = new _server_Server__WEBPACK_IMPORTED_MODULE_21__[\"default\"]({\n dataDir: \"./data\",\n filePath: \"testdemo\"\n });\n super(null, cfg, server, viewer);\n /** 是否是聚焦分布模式 */\n this._focusPartial = false;\n /** 根据构建检测检测得到的构建分布字符串数组结果 */\n this._partialObjectIds = [];\n /** 当前聚焦的分布索引 */\n this._partialFocusIndex = 0;\n /** 是否已加载metadata */\n this._metaLoaded = false;\n /**\n * 按照指定角度旋转相机\n * @param {number} angleInc\n * @returns\n */\n this.orbitYawCamera = (angleInc) => {\n return new Promise((resolve, reject) => {\n try {\n this.viewer.scene.camera.orbitYaw(angleInc);\n resolve(); // 执行成功时调用 resolve\n }\n catch (error) {\n reject(error); // 发生错误时调用 reject\n }\n });\n };\n this.cameraEnable = (pointerEnabled = !this.viewer.cameraControl.pointerEnabled) => {\n this.viewer.cameraControl.pointerEnabled = pointerEnabled;\n };\n /**\n * 模型截图\n * @param width\n * @param height\n * @param isDownload\n * @returns\n */\n this.shot = (width, height, isDownload) => {\n const canvas = document.getElementById(\"myCanvas\");\n const link = document.createElement(\"a\");\n link.download = \"screenshot.png\";\n const tempCanvas = document.createElement(\"canvas\");\n console.log(\"tempCanvas\", tempCanvas);\n const tempCtx = tempCanvas.getContext(\"2d\");\n if (canvas && tempCtx) {\n tempCanvas.width = width;\n tempCanvas.height = height;\n const scaleX = width / canvas.width;\n const scaleY = height / canvas.height;\n const scale = Math.max(scaleX, scaleY);\n const scaledWidth = canvas.width * scale;\n const scaledHeight = canvas.height * scale;\n const offsetX = (width - scaledWidth) / 2;\n const offsetY = (height - scaledHeight) / 2;\n tempCtx.clearRect(0, 0, width, height);\n tempCtx.fillStyle = \"transparent\"; // 设置透明色\n tempCtx.fillRect(0, 0, width, height);\n tempCtx.drawImage(canvas, 0, 0, canvas.width, canvas.height, 0, 0, 1, 1);\n // tempCtx.drawImage(canvas, 0, 0, canvas.width, canvas.height, offsetX, offsetY, scaledWidth, scaledHeight);\n if (isDownload) {\n tempCanvas.toBlob(function (blob) {\n const url = URL.createObjectURL(blob);\n link.href = url;\n link.click();\n URL.revokeObjectURL(url);\n });\n }\n return tempCanvas.toDataURL(\"image/png\");\n }\n return \"\";\n };\n this._configs = {};\n this._eventTrigger = new _EventTrigger__WEBPACK_IMPORTED_MODULE_2__[\"default\"]();\n this.navCubeCanvasElement = cfg.navCubeCanvasElement;\n this.viewerElement = cfg.viewerElement;\n this._modelId = cfg.modelId;\n this._hasOutlier = false;\n this._outlierObjectIds = [];\n this.viewer = viewer;\n this._objectsKdTree3 = new _collision_ObjectsKdTree3__WEBPACK_IMPORTED_MODULE_17__[\"default\"]({\n viewer\n });\n this._customizeViewer();\n this._modelsExplorer = new _explorer_ModelsExplorer__WEBPACK_IMPORTED_MODULE_11__[\"default\"](this, {\n enableEditModels: false,\n modelFromOutSide: true,\n modelType: cfg.modelType,\n modelContent: cfg.modelContent,\n modelSrc: cfg.modelSrc ? cfg.modelSrc : \"/\",\n modelMetaData: cfg.modelMetaData,\n modelConfig: cfg.modelConfig,\n IfcAPI: cfg.IfcAPI,\n WebIFC: cfg.WebIFC\n });\n this._objectsExplorer = new _explorer_ObjectsExplorer__WEBPACK_IMPORTED_MODULE_12__[\"default\"](this, {\n modelType: cfg.modelType\n });\n this._classesExplorer = new _explorer_ClassesExplorer__WEBPACK_IMPORTED_MODULE_13__[\"default\"](this, {\n modelType: cfg.modelType\n });\n this._storeysExplorer = new _explorer_StoreysExplorer__WEBPACK_IMPORTED_MODULE_14__[\"default\"](this, {\n modelType: cfg.modelType\n });\n // 重置相机视角的按钮(小房子图标)\n this._resetAction = new _toolbar_ResetAction__WEBPACK_IMPORTED_MODULE_4__[\"default\"](this, {});\n // 将相机视角放到最合适的位置的图标\n this._fitAction = new _toolbar_FitAction__WEBPACK_IMPORTED_MODULE_5__[\"default\"](this, {});\n // Allows Three-D and First Person toggle buttons to cooperatively switch\n // CameraControl#navMode between \"orbit\", \"firstPerson\" and \"planView\" modes\n class NavModeMediator {\n constructor(bimViewer) {\n this.threeDActive = false;\n this.firstPersonActive = false;\n this.setThreeDModeActive = (active) => {\n if (active) {\n bimViewer._firstPersonMode.setActive(false);\n bimViewer.viewer.cameraControl.navMode = \"orbit\";\n }\n else {\n bimViewer._firstPersonMode.setActive(false);\n bimViewer.viewer.cameraControl.navMode = \"planView\";\n }\n this.threeDActive = active;\n };\n this.setFirstPersonModeActive = (active) => {\n bimViewer.viewer.cameraControl.navMode = active ? \"firstPerson\" : this.threeDActive ? \"orbit\" : \"planView\";\n this.firstPersonActive = active;\n };\n }\n }\n const cameraControlNavModeMediator = new NavModeMediator(this);\n this._threeDMode = new _toolbar_ThreeDMode__WEBPACK_IMPORTED_MODULE_15__[\"default\"](this, {\n cameraControlNavModeMediator\n });\n this._orthoMode = new _toolbar_OrthoMode__WEBPACK_IMPORTED_MODULE_16__[\"default\"](this, {});\n this._firstPersonMode = new _toolbar_FirstPersonMode__WEBPACK_IMPORTED_MODULE_6__[\"default\"](this, {\n cameraControlNavModeMediator\n });\n this._hideTool = new _toolbar_HideTool__WEBPACK_IMPORTED_MODULE_7__[\"default\"](this, {});\n this._annotationTool = new _toolbar_AnnotationTool__WEBPACK_IMPORTED_MODULE_18__[\"default\"](this, {\n modelId: this._modelId\n });\n this._measureTool = new _toolbar_MeasureTool__WEBPACK_IMPORTED_MODULE_19__[\"default\"](this, {});\n this._sectionTool = new _toolbar_SectionTool__WEBPACK_IMPORTED_MODULE_9__[\"default\"](this, {});\n this._commentsTool = new _toolbar_CommentsTool__WEBPACK_IMPORTED_MODULE_20__[\"default\"](this, {});\n this._showSpacesMode = new _toolbar_ShowSpacesMode__WEBPACK_IMPORTED_MODULE_8__[\"default\"](this, {});\n this._navCubeMode = new _toolbar_NavCubeMode__WEBPACK_IMPORTED_MODULE_10__[\"default\"](this, {\n navCubeCanvasElement: this.navCubeCanvasElement,\n viewerElement: this.viewerElement\n });\n this._threeDMode.setActive(true);\n this._firstPersonMode.setActive(false);\n this._navCubeMode.setActive(true);\n this._annotationTool.setActive(false);\n this._measureTool.setActive(false);\n this._modelsExplorer.on(\"modelLoaded\", (modelId) => {\n this.fire(\"modelLoaded\", modelId);\n });\n this._modelsExplorer.on(\"modelUnloaded\", (modelId) => {\n this.fire(\"modelUnloaded\", modelId);\n });\n this._resetAction.on(\"reset\", () => {\n this.fire(\"reset\", true);\n });\n this._mutexActivation([this._hideTool, this._sectionTool, this._annotationTool]);\n this._bcfViewpointsPlugin = new _xtctwins_tctwins_core__WEBPACK_IMPORTED_MODULE_0__.BCFViewpointsPlugin(this.viewer, {});\n this._initConfigs();\n this._initSingleClickEvent();\n this._initRightClickEvent();\n this._initDoubleClickEvent();\n let treeReady = 0;\n this.eventTrigger.on(\"treeReady\", () => {\n treeReady++;\n if (treeReady === 3) {\n this.eventTrigger.emit(\"treeAllReady\", {\n objectsData: this.objectsExplorer.rootNode,\n classesData: this.classesExplorer.rootNode,\n storeysData: this.storeysExplorer.rootNode\n });\n }\n });\n }\n //------------------------------------------------------------------------------------------------------------------\n // 信息和服务\n //------------------------------------------------------------------------------------------------------------------\n get eventTrigger() {\n return this._eventTrigger;\n }\n /**\n * Returns the LocaleService that was configured on this Viewer.\n *\n * @return {LocaleService} The LocaleService.\n */\n get localeService() {\n return this.viewer.localeService;\n }\n //------------------------------------------------------------------------------------------------------------------\n // 点击事件\n //------------------------------------------------------------------------------------------------------------------\n /**\n * 初始化单击事件\n */\n _initSingleClickEvent() {\n this.viewer.cameraControl.on(\"mouseDownEntity\", (e) => {\n if (this.measureAngleTool.getActive() || this.measureDistanceTool.getActive())\n return;\n if (this.sectionTool.getActive() || this.annotationTool.getActive())\n return;\n e.preventDefault;\n const hit = this.viewer.scene.pick({\n canvasPos: e.canvasPos\n });\n if (hit) {\n if (hit.entity) {\n this.singleChoseEntity(hit.entity);\n this._eventTrigger.emit(\"pickedEntity\", hit.entity);\n }\n }\n });\n this.viewer.cameraControl.on(\"mouseDownNothing\", () => {\n if (this.measureAngleTool.getActive() || this.measureDistanceTool.getActive())\n return;\n if (this.sectionTool.getActive() || this.annotationTool.getActive())\n return;\n this.singleChosedSpace();\n this._eventTrigger.emit(\"pickedNothing\");\n });\n this.viewer.cameraControl.on(\"touchPicked\", (e) => {\n if (this.measureAngleTool.getActive() || this.measureDistanceTool.getActive())\n return;\n if (this.sectionTool.getActive() || this.annotationTool.getActive())\n return;\n e.preventDefault;\n const hit = this.viewer.scene.pick({\n canvasPos: e.canvasPos\n });\n if (hit) {\n if (hit.entity) {\n this.singleChoseEntity(hit.entity);\n this._eventTrigger.emit(\"touchEntity\", hit.entity);\n }\n }\n });\n this.viewer.cameraControl.on(\"touchPickedNothing\", () => {\n if (this.measureAngleTool.getActive() || this.measureDistanceTool.getActive())\n return;\n if (this.sectionTool.getActive() || this.annotationTool.getActive())\n return;\n this.singleChosedSpace();\n this._eventTrigger.emit(\"pickedNothing\");\n });\n }\n /**\n * 初始化右键事件\n */\n _initRightClickEvent() {\n this.viewer.cameraControl.on(\"rightClick\", (e) => {\n e.preventDefault;\n const hit = this.viewer.scene.pick({\n canvasPos: e.canvasPos\n });\n if (hit)\n this._eventTrigger.emit(\"rightPicked\", hit.entity);\n else {\n this._eventTrigger.emit(\"rightPickedNothing\");\n }\n });\n }\n /**\n * 初始化双击事件\n */\n _initDoubleClickEvent() {\n this.viewer.cameraControl.on(\"doublePicked\", (e) => {\n if (this.measureAngleTool.getActive() || this.measureDistanceTool.getActive())\n return;\n if (this.sectionTool.getActive() || this.annotationTool.getActive())\n return;\n e.preventDefault;\n const hit = this.viewer.scene.pick({\n canvasPos: e.canvasPos\n });\n if (hit) {\n if (hit.entity) {\n this.doubleChoseEntity(hit.entity);\n this._eventTrigger.emit(\"doublePicked\", hit.entity);\n }\n }\n });\n this.viewer.cameraControl.on(\"doublePickedNothing\", () => {\n if (this.measureAngleTool.getActive() || this.measureDistanceTool.getActive())\n return;\n if (this.sectionTool.getActive() || this.annotationTool.getActive())\n return;\n this.choseSpace();\n this._eventTrigger.emit(\"doublePickedNothing\");\n });\n }\n //------------------------------------------------------------------------------------------------------------------\n // 配置\n //------------------------------------------------------------------------------------------------------------------\n _customizeViewer() {\n const { scene } = this.viewer;\n // Emphasis effects\n scene.xrayMaterial.fill = false;\n scene.xrayMaterial.fillAlpha = 0.3;\n scene.xrayMaterial.fillColor = [0, 0, 0];\n scene.xrayMaterial.edges = true;\n scene.xrayMaterial.edgeAlpha = 0.1;\n scene.xrayMaterial.edgeColor = [0, 0, 0];\n // scene.highlightMaterial.edges = false;\n // scene.highlightMaterial.edgeColor = [0, 0.6, 1];\n // scene.highlightMaterial.edgeAlpha = 0.9;\n // scene.highlightMaterial.fill = true;\n scene.highlightMaterial.fillAlpha = 0.1;\n scene.highlightMaterial.fillColor = [0.6, 0.7, 0.8];\n //------------------------------------------------------------------------------------------------------------------\n // Configure points material\n //------------------------------------------------------------------------------------------------------------------\n scene.pointsMaterial.pointSize = 1;\n scene.pointsMaterial.roundPoints = true;\n scene.pointsMaterial.perspectivePoints = true;\n scene.pointsMaterial.minPerspectivePointSize = 2;\n scene.pointsMaterial.maxPerspectivePointSize = 4;\n // Camera control\n this.viewer.cameraControl.panRightClick = true;\n this.viewer.cameraControl.followPointer = true;\n this.viewer.cameraControl.doublePickFlyTo = false;\n this.viewer.cameraControl.smartPivot = true;\n // Dolly tweaks for best precision when aligning camera for BCF snapshots\n this.viewer.cameraControl.keyboardDollyRate = 100.0;\n this.viewer.cameraControl.mouseWheelDollyRate = 100.0;\n this.viewer.cameraControl.dollyInertia = 0;\n this.viewer.cameraControl.dollyMinSpeed = 0.04;\n this.viewer.cameraControl.dollyProximityThreshold = 30.0;\n const cameraPivotElement = document\n .createRange()\n .createContextualFragment(\"<div class='tctwins-camera-pivot-marker'></div>\").firstChild;\n this.viewer.scene.canvas.canvas.parentNode.appendChild(cameraPivotElement);\n this.viewer.cameraControl.pivotElement = cameraPivotElement;\n scene.camera.perspective.near = 0.01;\n scene.camera.perspective.far = 3000.0;\n scene.camera.ortho.near = 0.01;\n scene.camera.ortho.far = 2000.0; //\n // Scalable Ambient Obscurance (SAO) defaults\n // Since SAO is non-interactive, set to higher-quality\n const { sao } = scene;\n sao.enabled = false;\n sao.numSamples = 50;\n sao.kernelRadius = 200;\n }\n _initConfigs() {\n this.setConfigs({\n cameraNear: \"0.05\",\n cameraFar: \"3000.0\",\n smartPivot: true,\n saoEnabled: false,\n pbrEnabled: true,\n saoBias: \"0.5\",\n saoIntensity: \"0.15\",\n saoNumSamples: \"40\",\n saoKernelRadius: \"100\",\n edgesEnabled: false,\n xrayContext: true,\n xrayPickable: true,\n selectedGlowThrough: true,\n highlightGlowThrough: true,\n backgroundTransparency: true,\n backgroundColor: [1, 1.0, 1.0],\n objectColorSource: \"model\",\n externalMetadata: false,\n dtxEnabled: true,\n snapRadius: 20\n });\n }\n /**\n * Sets a batch of viewer configurations.\n *\n * Note that this method is not to be confused with {@link BIMViewer#setViewerState}, which batch-updates various states of the viewer's UI and 3D view.\n *\n * See [Viewer Configurations] for the list of available configurations.\n *\n * @param {*} viewerConfigs Map of key-value configuration pairs.\n */\n setConfigs(viewerConfigs) {\n for (const name in viewerConfigs) {\n if (Object.prototype.hasOwnProperty.call(viewerConfigs, name)) {\n const value = viewerConfigs[name];\n this.setConfig(name, value);\n }\n }\n // viewerConfigs.forEach((name: string) => {\n // if (Object.prototype.hasOwnProperty.call(viewerConfigs, name)) {\n // const value = viewerConfigs[name];\n // this.setConfig(name, value);\n // }\n // });\n }\n /**\n * Sets a viewer configuration.\n *\n * See [Viewer Configurations] for the list of available configurations.\n *\n * @param {String} name Configuration name.\n * @param {*} value Configuration value.\n */\n setConfig(name, value) {\n function parseBool(value) {\n return value === true || value === \"true\";\n }\n try {\n switch (name) {\n case \"backgroundTransparency\":\n const transparent = value;\n this.setBackgroundTransparent(transparent);\n this._configs[name] = transparent;\n break;\n case \"backgroundColor\":\n if (this._configs.backgroundTransparency) {\n break;\n }\n const rgbColor = value;\n this.setBackgroundColor(rgbColor);\n this._configs[name] = rgbColor;\n break;\n case \"cameraNear\":\n const near = parseFloat(value);\n this.viewer.scene.camera.perspective.near = near;\n this.viewer.scene.camera.ortho.near = near;\n this._configs[name] = near;\n break;\n case \"cameraFar\":\n const far = parseFloat(value);\n this.viewer.scene.camera.perspective.far = far;\n // this.viewer.scene.camera.ortho.far = far;\n this._configs[name] = far;\n break;\n case \"smartPivot\":\n this.viewer.cameraControl.smartPivot = this._configs[name] = parseBool(value);\n break;\n case \"saoEnabled\":\n // todo:\n this.viewer.scene.saoEnabled = this._configs[name] = parseBool(value);\n break;\n case \"saoBias\":\n this.viewer.scene.sao.bias = parseFloat(value);\n break;\n case \"saoIntensity\":\n this.viewer.scene.sao.intensity = parseFloat(value);\n break;\n case \"saoKernelRadius\":\n this.viewer.scene.sao.kernelRadius = this._configs[name] = parseFloat(value);\n break;\n case \"saoNumSamples\":\n this.viewer.scene.sao.numSamples = this._configs[name] = parseFloat(value);\n break;\n case \"saoBlur\":\n this.viewer.scene.sao.blur = this._configs[name] = parseBool(value);\n break;\n case \"edgesEnabled\":\n this.setEdgesEnabled(value);\n break;\n case \"pbrEnabled\":\n // this.viewer.scene.pbrEnabled = this._configs[name] = parseBool(value);\n break;\n case \"viewFitFOV\":\n this.viewer.cameraFlight.fitFOV = this._configs[name] = parseFloat(value);\n break;\n case \"viewFitDuration\":\n this.viewer.cameraFlight.duration = this._configs[name] = parseFloat(value);\n break;\n case \"perspectiveFOV\":\n this.viewer.camera.perspective.fov = this._configs[name] = parseFloat(value);\n break;\n case \"excludeUnclassifiedObjects\":\n this._configs[name] = parseBool(value);\n break;\n case \"objectColorSource\":\n this.setObjectColorSource(value);\n this._configs[name] = value;\n break;\n case \"xrayContext\":\n this._configs[name] = value;\n break;\n case \"xrayPickable\":\n this._configs[name] = parseBool(value);\n break;\n case \"selectedGlowThrough\":\n const selectedGlowThrough = (this._configs[name] = parseBool(value));\n const { selectedMaterial } = this.viewer.scene;\n selectedMaterial.glowThrough = selectedGlowThrough;\n selectedMaterial.fillAlpha = selectedGlowThrough ? 0.5 : 1.0;\n selectedMaterial.edgeAlpha = selectedGlowThrough ? 0.5 : 1.0;\n break;\n case \"highlightGlowThrough\":\n const highlightGlowThrough = (this._configs[name] = parseBool(value));\n const { highlightMaterial } = this.viewer.scene;\n highlightMaterial.glowThrough = highlightGlowThrough;\n highlightMaterial.fillAlpha = highlightGlowThrough ? 0.1 : 1.0;\n highlightMaterial.edgeAlpha = highlightGlowThrough ? 0.1 : 1.0;\n break;\n case \"externalMetadata\":\n this._configs[name] = value;\n break;\n case \"showSpaces\":\n // this._configs[name] = parseBool(value);\n this._showSpacesMode.setActive(value);\n break;\n case \"dtxEnabled\":\n this._configs[name] = parseBool(value);\n this.viewer.scene.dtxEnabled = value;\n break;\n case \"snapRadius\":\n this.setSnapRadius(value);\n break;\n default:\n this.error(`setConfig() - unsupported configuration: '${name}'`);\n }\n }\n catch (e) {\n this.error(`setConfig() - failed to configure ${name}: ${e}`);\n }\n }\n /**\n * Gets the value of a viewer configuration.\n *\n * These are set with {@link BIMViewer#setConfig} and {@link BIMViewer#setConfigs}.\n *\n * @param {String} name Configuration name.\n * @ereturns {*} Configuration value.\n */\n getConfig(name) {\n return this._configs[name];\n }\n getConfigs() {\n return this._configs;\n }\n //------------------------------------------------------------------------------------------------------------------\n // 查询\n //------------------------------------------------------------------------------------------------------------------\n /**\n * Returns the IDs of the models in the currently loaded project.\n *\n * @returns {String[]} The IDs of the models in the currently loaded project.\n */\n modelId() {\n return this._modelId;\n }\n /**\n * Loads a model into the viewer.\n *\n * Assumes that the project containing the model is currently loaded.\n *\n * @param {String} modelId ID of the model to load. Must be the ID of one of the models in the currently loaded project.\n * @param {Function} done Callback invoked on success.\n * @param {Function} error Callback invoked on failure, into which the error message string is passed.\n */\n loadModel(done, error) {\n if (!done)\n done = () => { };\n if (!error)\n error = () => { };\n this._modelsExplorer.loadModel(this._modelId, () => {\n done();\n }, (errorMsg) => {\n // this.error(`loadModel() - ${errorMsg}`);\n error(errorMsg);\n });\n }\n /**\n * 单独加载元数据\n * @param deflatedMetadata\n */\n loadMetadata(deflatedMetadata, force = true, done) {\n this._modelsExplorer.loadMetadata(this.viewer.metaScene.metaModels[this._modelId], deflatedMetadata, force, () => {\n this._metaLoaded = true;\n if (this._focusPartial) {\n this.viewFitPartial(0, done);\n }\n else {\n done;\n }\n });\n }\n /**\n * Sets where the colors for model objects will be loaded from.\n *\n * Options are:\n *\n * * \"model\" - (default) load colors from models, and\n * * \"viewer\" - load colors from the viewer's inbuilt table of colors for IFC types.\n *\n * This is \"model\" by default.\n *\n * @param {String} source Where colors will be loaded from - \"model\" or \"viewer\".\n */\n setObjectColorSource(source) {\n switch (source) {\n case \"model\":\n break;\n case \"viewer\":\n break;\n default:\n source = \"model\";\n this.error(\"setObjectColorSource() - Unsupported value - accepted values are 'model' and 'viewer' - defaulting to 'model'\");\n return;\n }\n this._objectColorSource = source;\n }\n /**\n * 获取构件属性\n * @param objectId\n * @returns\n */\n getObjectProperties(objectId) {\n const metaObject = this.viewer.metaScene.metaObjects[objectId];\n if (!metaObject) {\n return null;\n }\n const info = {\n id: metaObject.id,\n name: metaObject.name,\n type: metaObject.type,\n propertySets: []\n };\n const { propertySets } = metaObject;\n if (propertySets && propertySets.length > 0) {\n for (let i = 0; i < propertySets.length; i++) {\n const properties = propertySets[i].properties;\n const propertyList = [];\n for (let j = 0; j < properties.length; j++) {\n const properValue = {};\n properValue[properties[j].name] = properties[j].value;\n propertyList.push(properValue);\n }\n const propertyset = {\n id: propertySets[i].id,\n name: propertySets[i].name,\n properties: propertyList,\n type: propertySets[i].type\n };\n info.propertySets.push(propertyset);\n }\n }\n return info;\n }\n /**\n * 获取模型信息\n * @returns\n */\n getModelInfo() {\n const metaModel = this.viewer.metaScene.metaModels[this._modelId];\n const modelInfo = {\n id: metaModel.id,\n createDate: metaModel.createdAt ? metaModel.createdAt : \"\",\n author: metaModel.author ? metaModel.author : \"\",\n objectCount: metaModel.objectCount ? metaModel.objectCount : \"\",\n propertySetCount: metaModel.propertySetCount ? metaModel.propertySetCount : \"\"\n };\n return modelInfo;\n }\n //------------------------------------------------------------------------------------------------------------------\n // 视图设置\n //------------------------------------------------------------------------------------------------------------------\n /**\n * Sets whether or not the given objects are visible.\n *\n * @param {String[]} objectIds IDs of objects.\n * @param {Boolean} visible True to set objects visible, false to set them invisible.\n */\n setObjectsVisible(objectIds, visible) {\n this._withObjectsInSubtree(objectIds, (entity) => {\n entity.visible = visible;\n });\n }\n /**\n * Sets whether or not the given objects are selected.\n *\n * @param {String[]} objectIds IDs of objects.\n * @param {Boolean} selected Whether or not to set the objects selected.\n */\n setObjectsSelected(objectIds, selected) {\n this._withObjectsInSubtree(objectIds, (entity) => {\n entity.selected = selected;\n });\n }\n /**\n * Sets whether or not the given objects are X-rayed.\n *\n * @param {String[]} objectIds IDs of objects.\n * @param {Boolean} xrayed Whether or not to X-ray the objects.\n */\n setObjectsXRayed(objectIds, xrayed) {\n this._withObjectsInSubtree(objectIds, (entity) => {\n entity.xrayed = xrayed;\n });\n }\n _withObjectsInSubtree(objectIds, callback) {\n if (!objectIds) {\n this.error(\"Argument expected: objectIds\");\n return;\n }\n objectIds.forEach((objectId) => {\n // const objectId = objectIds[index];\n this.viewer.metaScene.withMetaObjectsInSubtree(objectId, (metaObject) => {\n const entity = this.viewer.scene.objects[metaObject.id];\n if (entity) {\n callback(entity);\n }\n });\n });\n }\n /**\n * Flies the camera to fit the given object in view.\n *\n * @param {String} objectId ID of the object\n * @param {Function} done Callback invoked on completion\n */\n flyToObject(objectId, done) {\n if (!objectId) {\n this.error(\"flyToObject() - Argument expected: objectId\");\n return;\n }\n const { viewer } = this;\n const { scene } = viewer;\n const objectIds = [];\n this.viewer.metaScene.withMetaObjectsInSubtree(objectId, (metaObject) => {\n if (scene.objects[metaObject.id]) {\n objectIds.push(metaObject.id);\n }\n });\n if (objectIds.length === 0) {\n this.error(`Object not found in viewer: '${objectId}'`);\n if (done) {\n done();\n }\n return;\n }\n scene.setObjectsVisible(objectIds, true);\n scene.setObjectsHighlighted(objectIds, true);\n const aabb = scene.getAABB(objectIds);\n viewer.cameraFlight.flyTo({\n aabb\n }, () => {\n if (done) {\n done();\n }\n setTimeout(() => {\n scene.setObjectsHighlighted(scene.highlightedObjectIds, false);\n }, 500);\n });\n viewer.cameraControl.pivotPos = _xtctwins_tctwins_core__WEBPACK_IMPORTED_MODULE_0__.math.getAABB3Center(aabb);\n }\n /**\n * Flies the camera to fit the given objects in view.\n *\n * @param {String[]} objectIds IDs of the objects\n * @param {Function} done Callback invoked on completion\n */\n viewFitObjects(objectIds, done) {\n if (!objectIds) {\n this.error(\"flyToObject() - Argument expected: objectIds\");\n return;\n }\n const { viewer } = this;\n const { scene } = viewer;\n const entityIds = [];\n objectIds.forEach((objectId) => {\n this.viewer.metaScene.withMetaObjectsInSubtree(objectId, (metaObject) => {\n if (scene.objects[metaObject.id]) {\n entityIds.push(metaObject.id);\n }\n });\n });\n if (entityIds.length === 0) {\n if (done) {\n done();\n }\n return;\n }\n scene.setObjectsVisible(entityIds, true);\n scene.setObjectsHighlighted(entityIds, true);\n const aabb = scene.getAABB(entityIds);\n viewer.cameraFlight.flyTo({\n aabb\n }, () => {\n if (done) {\n done();\n }\n setTimeout(() => {\n scene.setObjectsHighlighted(scene.highlightedObjectIds, false);\n }, 500);\n });\n viewer.cameraControl.pivotPos = _xtctwins_tctwins_core__WEBPACK_IMPORTED_MODULE_0__.math.getAABB3Center(aabb);\n }\n /**\n * 相机立刻聚焦到指定构建id的对象,没有转移视角动画\n * @param {String} objectId\n */\n jumpToObjects(objectIds) {\n if (!objectIds) {\n this.error(\"jumpToObject() - Argument expected: objectIds\");\n return;\n }\n const { viewer } = this;\n const { scene } = viewer;\n const entityIds = [];\n this.viewer.metaScene.withMetaObjectsInSubtree(objectIds, (metaObject) => {\n if (scene.objects[metaObject.id]) {\n entityIds.push(metaObject.id);\n }\n });\n if (entityIds.length === 0) {\n this.error(`Objects not found in viewer: '${objectIds}'`);\n return;\n }\n scene.setObjectsVisible(entityIds, true);\n const aabb = scene.getAABB(entityIds);\n viewer.cameraFlight.jumpTo({\n aabb\n });\n viewer.cameraControl.pivotPos = _xtctwins_tctwins_core__WEBPACK_IMPORTED_MODULE_0__.math.getAABB3Center(aabb);\n }\n /**\n * 设置相机位置\n * @param {Number[]} [params.eye] Eye position.\n * @param {Number[]} [params.look] Point of interest.\n * @param {Number[]} [params.up] Direction of \"up\".\n */\n setCamera(params) {\n const { viewer } = this;\n const { scene } = viewer;\n const { camera } = scene;\n if (params.eye) {\n camera.eye = params.eye;\n }\n if (params.look) {\n camera.look = params.look;\n }\n if (params.up) {\n camera.up = params.up;\n }\n }\n /**\n * 相机移动到指定视角\n * @param {Number[]} [params.eye] 相机位置.\n * @param {Number[]} [params.look] 相机视点\n * @param {Number[]} [params.up] 上方方向\n */\n flyToNewView(params) {\n this.viewer.cameraControl.pivotPos = params.look;\n this.viewer.cameraFlight.flyTo({\n look: params.look,\n eye: params.eye,\n up: params.up,\n duration: params.duration\n });\n }\n /**\n * Fits the given models in view.\n *\n * @param {String[]} modelIds ID of the models.\n * @param {Function} [done] Callback invoked on completion. Will be animated if this is given, otherwise will be instantaneous.\n */\n viewFitModels(modelIds, done) {\n if (!modelIds) {\n this.error(\"viewFitModels() - Argument expected: modelIds\");\n return;\n }\n const { viewer } = this;\n const { scene } = viewer;\n const aabb = _xtctwins_tctwins_core__WEBPACK_IMPORTED_MODULE_0__.math.AABB3();\n _xtctwins_tctwins_core__WEBPACK_IMPORTED_MODULE_0__.math.collapseAABB3(aabb);\n modelIds.forEach((modelId) => {\n const model = scene.models[modelId];\n if (model) {\n model.visible = true;\n model.highlighted = true;\n _xtctwins_tctwins_core__WEBPACK_IMPORTED_MODULE_0__.math.expandAABB3(aabb, model.aabb);\n }\n else {\n this.error(`Model not found in viewer: '${modelId}'`);\n }\n });\n if (done) {\n viewer.cameraFlight.flyTo({\n aabb\n }, () => {\n done();\n setTimeout(() => {\n scene.setObjectsHighlighted(scene.highlightedObjectIds, false);\n }, 500);\n });\n }\n else {\n viewer.cameraFlight.jumpTo({\n aabb\n });\n setTimeout(() => {\n scene.setObjectsHighlighted(scene.highlightedObjectIds, false);\n }, 500);\n }\n viewer.cameraControl.pivotPos = _xtctwins_tctwins_core__WEBPACK_IMPORTED_MODULE_0__.math.getAABB3Center(aabb);\n }\n /**\n * 切换模型分布 - 根据构建检测结果的模型分布情况聚焦不同分布区域\n *\n * 使用:\n * bimViewer.viewFitPartial(1, (partNum:number)=>{\n * console.log(partNum); //当前聚焦的模型分布索引\n * })\n *\n * bimViewer.viewFitPartial((partNum:number)=>{\n * console.log(partNum); //当前聚焦的模型分布索引\n * })\n *\n * bimViewer.viewFitPartial(1); //无回调方法。自动切换分布视角\n *\n * bimViewer.viewFitPartial(); //无指定索引输入,无回调方法。自动切换分布视角\n *\n *\n * @param {number} part - 模型分布索引(例如:根据检测结果,当前模型有三块模型分布,则可以输入[0-2]区间的数字)\n * @param {Function} done -\n */\n viewFitPartial(part, done) {\n let partNum;\n if (typeof part === \"function\") {\n done = part;\n partNum = this._partialFocusIndex += 1;\n }\n else {\n partNum = part !== null && part !== void 0 ? part : (this._partialFocusIndex += 1);\n }\n if (partNum >= 0 && partNum < this._partialObjectIds.length) {\n this.viewFitObjects(this._partialObjectIds[partNum], () => {\n for (let i = 0; i < this._partialObjectIds.length; i++) {\n if (partNum == i)\n this.setObjectsVisible(this._partialObjectIds[i], true);\n else\n this.setObjectsVisible(this._partialObjectIds[i], false);\n }\n done ? done(partNum) : done;\n });\n }\n else {\n partNum = this._partialFocusIndex = 0;\n this.viewFitObjects(this._partialObjectIds[partNum], () => {\n for (let i = 0; i < this._partialObjectIds.length; i++) {\n if (partNum == i)\n this.setObjectsVisible(this._partialObjectIds[i], true);\n else\n this.setObjectsVisible(this._partialObjectIds[i], false);\n }\n done ? done(partNum) : done;\n });\n }\n }\n /**\n * 设置模型分布 - 根据构建检测结果设置不同分布位置的模型构建ID数组\n * @param {string[][]} partialObjectIds\n */\n setPartialObjectIds(partialObjectIds) {\n const newPartialIdsList = [];\n for (let i = 0; i < partialObjectIds.length; i++) {\n newPartialIdsList.push(partialObjectIds[i]);\n }\n this._partialObjectIds = newPartialIdsList;\n this.viewer.cameraControl.smartPivot = false;\n this.navCubeMode.fitVisible = true;\n this._focusPartial = true;\n if (this._metaLoaded)\n this.viewFitPartial(0);\n }\n /// /////////部分操作////////////////////////////////////////\n /**\n * Transitions the viewer into an isolated view of the given building storey.\n *\n * Does nothing and logs an error if no object of the given ID is in the viewer, or if the object is not an ````IfcBuildingStorey````.\n *\n * @param {String} storeyObjectId ID of an ````IfcBuildingStorey```` object.\n * @param {Function} [done] Optional callback to invoke on completion. When provided, the transition will be animated, with the camera flying into position. Otherwise, the transition will be instant, with the camera jumping into position.\n */\n selectStorey(storeyObjectId, done = () => { }) {\n const { metaScene } = this.viewer;\n const storeyMetaObject = metaScene.metaObjects[storeyObjectId];\n if (!storeyMetaObject) {\n this.error(`selectStorey() - Object is not found: '${storeyObjectId}'`);\n return;\n }\n if (storeyMetaObject.type !== \"IfcBuildingStorey\") {\n this.error(`selectStorey() - Object is not an IfcBuildingStorey: '${storeyObjectId}'`);\n return;\n }\n this._storeysExplorer.selectStorey(storeyObjectId, done);\n }\n /**\n * Sets whether or not keyboard camera control is enabled.\n *\n * This is useful when we don't want key events over the canvas to clash with other UI elements outside the canvas.\n *\n * Default value is ````true````.\n *\n * @param {Boolean} enabled Set ````true```` to enable keyboard input.\n */\n setKeyboardEnabled(enabled) {\n this.viewer.scene.input.keyboardEnabled = enabled;\n }\n /**\n * Gets whether keyboard camera control is enabled.\n *\n * This is useful when we don't want key events over the canvas to clash with other UI elements outside the canvas.\n *\n * Default value is ````true````.\n *\n * @returns {Boolean} Returns ````true```` if keyboard input is enabled.\n */\n getKeyboardEnabled() {\n return this.viewer.scene.input.keyboardEnabled;\n }\n /**\n * 缓冲对象spinner显隐设置\n * @param show\n */\n showSpinner(show = !this.viewer.scene.canvas.spinner.visible) {\n this.viewer.scene.canvas.spinner.visible = show;\n }\n /**\n * 更新包围盒 - 排除异常构建并更新包围盒\n * @param exceptionIDs - 异常构建ID\n * @param callback - 回调\n */\n updateAABB(exceptionIDs, callback) {\n if (exceptionIDs.length > 0) {\n this._hasOutlier = true;\n this._outlierObjectIds = exceptionIDs;\n }\n const model = this.viewer.scene.models[this._modelId];\n const newExceptionsIds = exceptionIDs.concat(model.exceptionIds);\n model.exceptionIds = newExceptionsIds;\n this.viewer.scene.setObjectsVisible(newExceptionsIds, false);\n this.viewer.scene.on(\"aabb\", () => {\n if (typeof callback === \"function\")\n callback();\n });\n }\n /**\n * 销毁\n */\n destroy(callback) {\n var _a;\n this.measureDistanceTool.destroy();\n this.measureAngleTool.destroy();\n this._annotationTool.destroy();\n this._commentsTool.destroy();\n this._bcfViewpointsPlugin.destroy();\n this._modelsExplorer.destroy();\n this._classesExplorer.destroy();\n this._objectsExplorer.destroy();\n this._storeysExplorer.destroy();\n this._eventTrigger.destroy();\n const dos = document.querySelector(\".tctwins-camera-pivot-marker\");\n if (dos) {\n (_a = dos.parentNode) === null || _a === void 0 ? void 0 : _a.removeChild(dos);\n }\n this.viewer.destroy(callback);\n }\n /// /////////右键菜单////////////////////////////////////////\n // 选中\n /**\n * 设置对象被选中与否\n * @param entity\n * @param selected\n */\n setEntitySelected(entity, selected = !entity.selected) {\n entity.selected = selected;\n }\n /**\n * 选中其他对象\n * @param entity\n */\n setOthersSelected(entity) {\n this.setAllObjectsSelected(true);\n this.setEntitySelected(entity, true);\n }\n /**\n * 设置全部选中与否\n * @param {Boolean} selected\n */\n setAllObjectsSelected(selected) {\n if (selected) {\n this.viewer.scene.setObjectsSelected(this.viewer.scene.objectIds, true);\n }\n else {\n this.viewer.scene.setObjectsSelected(this.viewer.scene.selectedObjectIds, false);\n }\n }\n // 聚焦\n /**\n * 设置相机适应选中对象\n * @param entity\n */\n viewFitEntity(entity) {\n const { scene } = this.viewer;\n this.viewer.cameraFlight.flyTo({\n aabb: entity.aabb,\n duration: 0.5\n }, () => {\n setTimeout(() => {\n scene.setObjectsHighlighted(scene.highlightedObjectIds, false);\n }, 500);\n });\n this.viewer.cameraControl.pivotPos = _xtctwins_tctwins_core__WEBPACK_IMPORTED_MODULE_0__.math.getAABB3Center(entity.aabb);\n }\n /**\n * 相机适应所有选中对象\n */\n viewFitSelectedObjects() {\n this.viewFitObjects(this.viewer.scene.highlightedObjectIds, () => { });\n }\n /**\n * Flies the camera to fit all objects in view.\n *\n * @param {Function} done Callback invoked on completion\n */\n viewFitAll(done) {\n if (this._focusPartial) {\n this.viewFitPartial(this._partialFocusIndex, done);\n return;\n }\n this._fitAction.fit(done);\n }\n // 隐藏\n /**\n * 设置选中对象隐藏与否\n * @param entity\n */\n setEntityHide(entity, visible = !entity.visible) {\n entity.visible = visible;\n }\n /**\n * 隐藏选中对象以外的其他模型对象\n * @param entity\n * @returns\n */\n setOthersHide(entity) {\n const metaObject = this.viewer.metaScene.metaObjects[entity.id];\n if (!metaObject) {\n return;\n }\n this.viewer.scene.setObjectsVisible(this.viewer.scene.visibleObjectIds, false);\n metaObject.withMetaObjectsInSubtree((metaObject) => {\n const entity = this.viewer.scene.objects[metaObject.id];\n if (entity) {\n entity.visible = true;\n }\n });\n }\n /**\n * 显示所有对象\n * @param {Boolean} visible True to set objects visible, false to set them invisible.\n */\n setAllObjectsVisible(visible) {\n if (visible) {\n this.viewer.scene.setObjectsVisible(this.viewer.scene.objectIds, true);\n if (this._hasOutlier)\n this.viewer.scene.setObjectsVisible(this._outlierObjectIds, false);\n }\n else {\n this.viewer.scene.setObjectsVisible(this.viewer.scene.visibleObjectIds, false);\n }\n }\n // 透视\n /**\n * 设置选中对象透视与否\n * @param entity\n * @param xrayed\n */\n setEntityXRayed(entity, xrayed = !entity.xrayed) {\n entity.xrayed = xrayed;\n entity.pickable = this.getConfig(\"xrayPickable\");\n }\n /**\n * 设置其他对象透视\n * @param entity\n * @returns\n */\n setOthersXRayed(entity) {\n const { scene } = this.viewer;\n const metaObject = this.viewer.metaScene.metaObjects[entity.id];\n if (!metaObject) {\n return;\n }\n scene.setObjectsVisible(scene.objectIds, true);\n scene.setObjectsXRayed(scene.objectIds, true);\n if (!this.getConfig(\"xrayPickable\")) {\n scene.setObjectsPickable(scene.objectIds, false);\n }\n metaObject.withMetaObjectsInSubtree((metaObject) => {\n const entity = scene.objects[metaObject.id];\n if (entity) {\n entity.xrayed = false;\n entity.pickable = true;\n }\n });\n }\n /**\n * 设置所有对象透视与否\n * @param {Boolean} xrayed Whether or not to set all objects X-rayed.\n */\n setAllObjectsXRayed(xrayed) {\n if (xrayed) {\n this.viewer.scene.setObjectsXRayed(this.viewer.scene.objectIds, true);\n }\n else {\n this.viewer.scene.setObjectsXRayed(this.viewer.scene.xrayedObjectIds, false);\n }\n }\n // 判断\n entityVisble(entity) {\n return entity.visible;\n }\n entityXRayed(entity) {\n return entity.xrayed;\n }\n entityChosed(entity) {\n return entity.selected;\n }\n /**\n * 判断是否有被隐藏的\n * @returns\n */\n hiddenMoreThanOne() {\n return this.viewer.scene.numObjects - this.viewer.scene.numVisibleObjects > 0;\n }\n /**\n * 判断是否有被透视的\n * @returns\n */\n xRayedMoreThanOne() {\n return this.viewer.scene.numXRayedObjects > 0;\n }\n /**\n * 判断是否有被选中的\n * @returns\n */\n SelectedMoreThanOne() {\n return this.viewer.scene.numSelectedObjects > 0;\n }\n /// /////////设置背景颜色,透明,边缘等 初始设置///////////////////////////\n /**\n * Sets the viewer's background color.\n *\n * @param {boolean}\n */\n setBackgroundTransparent(trans = !this.viewer.scene.backgroundTransparent) {\n this.viewer.scene.backgroundTransparent = trans;\n this.viewer.scene.render(true);\n }\n /**\n * Sets the viewer's background color.\n *\n * @param {Number[]} rgbColor Three-element array of RGB values, each in range ````[0..1]````.\n */\n setBackgroundColor(rgbColor) {\n this.viewer.scene.backgroundColor = rgbColor;\n this.viewer.scene.render(true);\n }\n /**\n * 设置导航盒尺寸\n * @param {number} size 默认是200\n */\n setNavCubeSize(size) {\n this.navCubeCanvasElement.style.width = `${size.toString()}px`;\n this.navCubeCanvasElement.style.height = `${size.toString()}px`;\n }\n /**\n * 设置导航盒的位置\n * @param {string} direction e.g.\"left\",\"right\",\"top\",\"bottom\"\n * @param {number} pos\n */\n setNavCubePosition(direction, pos) {\n switch (direction) {\n case \"top\":\n this.navCubeCanvasElement.style.top = `${pos.toString()}px`;\n this.navCubeCanvasElement.style.bottom = \"\";\n break;\n case \"bottom\":\n this.navCubeCanvasElement.style.top = \"\";\n this.navCubeCanvasElement.style.bottom = `${pos.toString()}px`;\n break;\n case \"right\":\n this.navCubeCanvasElement.style.left = \"\";\n this.navCubeCanvasElement.style.right = `${pos.toString()}px`;\n break;\n case \"left\":\n this.navCubeCanvasElement.style.right = \"\";\n this.navCubeCanvasElement.style.left = `${pos.toString()}px`;\n break;\n }\n }\n /**\n * 更新canvas\n */\n updateCanvas() {\n this.viewer.scene.canvas.dirtyBoundary = true;\n }\n /**\n * 设置测量鼠标偏移量\n * @param offsetX\n * @param offsetY\n */\n setMeasureOffSet(offsetX, offsetY) {\n this._measureTool.setMeasureOffSet(offsetX, offsetY);\n }\n /**\n * 设置批注鼠标偏移量\n * @param offsetX\n * @param offsetY\n */\n setCommentsOffset(offsetX, offsetY) {\n this._commentsTool.offsetX = offsetX;\n this._commentsTool.offsetY = offsetY;\n }\n /**\n * 设置测量鼠标吸附点灵敏度\n * @param radius\n */\n setSnapRadius(radius) {\n this.measureTool.setSnapRadius(radius);\n }\n /**\n * 设置是否是触屏模式\n * @param {boolean} isTouch\n */\n setIsTouch(isTouch) {\n this.sectionTool.isTouch = isTouch;\n this.commentTool.isTouch = isTouch;\n }\n /**\n * 调整光照强度 0-100\n * @param num\n */\n setLightIntensity(num) {\n if (num < 0 || num > 100)\n return;\n for (let name in this.viewer.scene.lightsObject) {\n this.viewer.scene.lightsObject[name].intensity = 0.63 + (num - 50) / 200;\n }\n }\n /**\n * 设置空间构建的颜色模式;默认 1\n * @param {number} colorState\n */\n setSpaceMaterialColor(colorState) {\n if (colorState === 1)\n this.viewer.scene.highlightMaterial.fillColor = [0.6, 0.7, 0.8];\n else if (colorState === 2)\n this.viewer.scene.highlightMaterial.fillColor = [0.2, 0.3, 0.4];\n }\n /////////////渲染设置//////////////////////\n /**\n * set edges Enable\n * @param {boolean} edgesEnabled\n */\n setEdgesEnabled(edgesEnabled = !this.viewer.scene.edgesEnabled) {\n this.viewer.scene.edgesEnabled = edgesEnabled;\n this.viewer.scene.render(true);\n }\n /**\n * 是否开启环境光\n * @param {boolean} saoEnabled\n */\n setSAOEnabled(saoEnabled = !this.viewer.scene.saoEnabled) {\n this.viewer.scene.saoEnabled = saoEnabled;\n }\n setDTXEnabled(dtxEnabled = !this.viewer.scene.dtxEnabled) {\n this.viewer.scene.dtxEnabled = dtxEnabled;\n }\n setPBREnabled(pbrEnabled = !this.viewer.scene.pbrEnabled) {\n this.viewer.scene.pbrEnabled = pbrEnabled;\n }\n /**\n * 视图复位 - 恢复默认视图\n */\n resetView(callback) {\n if (this._focusPartial) {\n this.setDirection(25);\n return;\n }\n this._resetAction.reset(callback);\n }\n /**\n * 自适应 - 在当前相机视角适应视图填充画面\n */\n fitView(callback) {\n if (this._focusPartial) {\n this.viewFitPartial(this._partialFocusIndex, callback);\n return;\n }\n this._fitAction.fit();\n }\n /**\n * 标注开关\n * @param active\n * @param callback\n */\n SetAnnotationToolActive(active = !this._annotationTool.getActive(), callback) {\n this._annotationTool.setActive(active);\n if (callback)\n callback(this._annotationTool.getActive());\n }\n /**\n * 批注开关\n * @param active\n * @param callback\n */\n SetCommentsToolActive(active = !this._commentsTool.getActive(), callback) {\n this._commentsTool.setActive(active);\n if (callback)\n callback(this._commentsTool.getActive());\n }\n /**\n * 第一人称视角\n * @param active\n * @param callback\n */\n SetFirstPersonModeActive(active = !this._firstPersonMode.getActive(), callback) {\n this._firstPersonMode.setActive(active);\n if (callback)\n callback(this._firstPersonMode.getActive());\n }\n /**\n * 测量工具统一开关\n * @param active\n * @param callback\n */\n SetMeasureToolActive(active = !this.measureAngleTool.getActive(), callback) {\n this._measureTool.setActive(active);\n if (callback)\n callback(this._measureTool.getActive());\n }\n /**\n * 角度测量开关\n * @param active\n * @param callback\n */\n SetMeasureAngleActive(active = !this.measureAngleTool.getActive(), callback) {\n this._measureTool.SetMeasureAngleActive(active);\n if (callback)\n callback(this.measureAngleTool.getActive());\n }\n /**\n * 距离测量开关\n * @param active\n * @param callback\n */\n SetMeasureDistanceActive(active = !this.measureDistanceTool.getActive(), callback) {\n this._measureTool.SetMeasureDistanceActive(active);\n if (callback)\n callback(this.measureDistanceTool.getActive());\n }\n /**\n * 剖切工具开关\n * @param active\n * @param callback\n */\n SetSectionToolActive(active = !this._sectionTool.getActive(), callback) {\n this._sectionTool.setActive(active);\n if (callback)\n callback(this._sectionTool.getActive());\n }\n /**\n * 隐藏工具开关\n * @param active\n * @param callback\n */\n SetHideToolActive(active, callback) {\n this._hideTool.setActive(active);\n if (callback)\n callback();\n }\n /**\n * 框选开关\n * @param active\n * @param callback\n */\n SetMarqueeSelectionActive(active, callback) {\n // this._marqueeSelectionTool.setActive(active);\n if (callback)\n callback();\n }\n /**\n * 相机视角开关\n * @param active\n * @param callback\n */\n SetOrthoModeActive(active = !this._orthoMode.getActive(), callback) {\n this._orthoMode.setActive(active, callback);\n }\n /**\n * 3d/2d视角开关\n * @param active\n * @param callback\n */\n SetThreeDModeActive(active = !this._threeDMode.getActive(), callback) {\n this._threeDMode.setActive(active, callback);\n }\n /**\n * 显示空间功能开关\n * @param active\n * @param callback\n */\n SetShowSpaceModeActive(active = !this._showSpacesMode.getActive(), callback) {\n this._showSpacesMode.setActive(active, callback);\n }\n /// ///////////////功能对象/////////////////////\n /**\n * 漫游\n */\n get firstPersonMode() {\n return this._firstPersonMode;\n }\n /**\n * 测量管理工具\n */\n get measureTool() {\n return this._measureTool;\n }\n /**\n * 角度测量\n */\n get measureAngleTool() {\n return this._measureTool.measureAngleTool;\n }\n /**\n * 距离测量\n */\n get measureDistanceTool() {\n return this._measureTool.measureDistanceTool;\n }\n /**\n * 剖切\n */\n get sectionTool() {\n return this._sectionTool;\n }\n /**\n * 批注\n */\n get commentTool() {\n return this._commentsTool;\n }\n /**\n * 标注\n */\n get annotationTool() {\n return this._annotationTool;\n }\n /**\n * 结构树object(对象)\n */\n get objectsExplorer() {\n return this._objectsExplorer;\n }\n /**\n * 结构树class(类别)\n */\n get classesExplorer() {\n return this._classesExplorer;\n }\n /**\n * 结构树storey(楼层)\n */\n get storeysExplorer() {\n return this._storeysExplorer;\n }\n /**\n * 模型加载器\n */\n get modelsExplorer() {\n return this._modelsExplorer;\n }\n /**\n * 相机视角\n */\n get orthoMode() {\n return this._orthoMode;\n }\n /**\n * 2D/3D\n */\n get threeDMode() {\n return this._threeDMode;\n }\n /**\n * 导航盒控制器对象\n */\n get navCubeMode() {\n return this._navCubeMode;\n }\n /////////////////////导航//////////////////////////\n /**\n * 设置相机方向\n * @param {number} dirNum\n */\n setDirection(dirNum) {\n this._navCubeMode.flyByClick(dirNum);\n }\n /**\n * 单击模型对象\n * @param entity\n */\n singleChoseEntity(entity) {\n // this.showObjectProperties(entity.id.toString()); //显示构建属性\n this.setAllObjectsSelected(false); //所有构件高亮取消\n this.setEntitySelected(entity); //选中构件高亮\n }\n /**\n * 单击点击空白\n */\n singleChosedSpace() {\n this.setAllObjectsSelected(false); //所有构件高亮取消\n }\n /**\n * 双击模型对象\n * @param entity\n */\n doubleChoseEntity(entity) {\n this.viewFitEntity(entity); //聚焦构件\n this.setAllObjectsSelected(false); //所有构件高亮取消\n this.setEntitySelected(entity); //选中构件高亮\n }\n /**\n * 回到正常视图\n */\n choseSpace() {\n this.setAllObjectsSelected(false);\n this.viewFitAll();\n }\n /**\n * 初始预览环周截图\n * @param sizeOrCallback\n * @param done\n * @returns\n */\n getPreShot(sizeOrCallback, done) {\n const cameraEnable = this.cameraEnable;\n cameraEnable(false);\n let size = typeof sizeOrCallback === \"function\" ? 1024 : sizeOrCallback;\n if (typeof sizeOrCallback === \"function\")\n done = sizeOrCallback;\n const orbitYawCamera = this.orbitYawCamera;\n const viewer = this.viewer;\n const canvas = document.createElement(\"canvas\");\n const ctx = canvas.getContext(\"2d\");\n const canvasWidth = size * 15;\n const canvasHeight = size;\n canvas.width = canvasWidth;\n canvas.height = canvasHeight;\n const imagesPromises = Array.from({ length: 15 }, () => processImage);\n function processImage() {\n return __awaiter(this, void 0, void 0, function* () {\n yield orbitYawCamera(-18);\n yield delay(100); // 添加延迟,确保相机完成旋转\n return getshot(size);\n });\n }\n function delay(ms) {\n return new Promise((resolve) => setTimeout(resolve, ms));\n }\n function getshot(size) {\n return __awaiter(this, void 0, void 0, function* () {\n const canvas = viewer.scene.canvas.canvas;\n const tempCanvas = document.createElement(\"canvas\");\n const tempCtx = tempCanvas.getContext(\"2d\");\n if (canvas && tempCtx) {\n tempCanvas.width = size;\n tempCanvas.height = size;\n const scaleX = size / canvas.width;\n const scaleY = size / canvas.height;\n const scale = Math.max(scaleX, scaleY);\n const scaledWidth = canvas.width * scale;\n const scaledHeight = canvas.height * scale;\n const offsetX = (size - scaledWidth) / 2;\n const offsetY = (size - scaledHeight) / 2;\n tempCtx.clearRect(0, 0, size, size);\n tempCtx.fillStyle = \"transparent\"; // 设置透明色\n tempCtx.fillRect(0, 0, size, size);\n tempCtx.drawImage(canvas, 0, 0, canvas.width, canvas.height, offsetX, offsetY, scaledWidth, scaledHeight);\n return new Promise((resolve, reject) => {\n const img = new Image();\n img.onload = () => resolve(img);\n img.onerror = reject;\n img.src = tempCanvas.toDataURL(); // 将 Canvas 转换为 data URL\n });\n }\n else {\n return Promise.reject(new Error(\"Canvas or context not found.\"));\n }\n });\n }\n function handleCanvasResult(download) {\n const imageData = canvas.toDataURL(\"image/png\");\n if (download) {\n const downloadLink = document.createElement(\"a\");\n downloadLink.href = imageData;\n downloadLink.download = \"combined_image.png\";\n downloadLink.click();\n }\n cameraEnable(true);\n if (done)\n done(imageData);\n return imageData;\n }\n (() => __awaiter(this, void 0, void 0, function* () {\n for (let i = 0; i < imagesPromises.length; i++) {\n try {\n const img = (yield imagesPromises[i]());\n if (ctx)\n ctx.drawImage(img, i * size, 0);\n }\n catch (error) {\n cameraEnable(true);\n console.error(\"获取图片内容失败:\", error);\n }\n }\n handleCanvasResult(false);\n }))();\n return \"\";\n }\n /**\n * 设置遮挡截图\n * @param callback\n */\n setShelterCanvas(callback) {\n const canvas = this.viewer.scene.canvas.canvas;\n const canvasImage = this.shot(canvas.width, canvas.height, false);\n const shelterImage = document.createElement(\"img\");\n shelterImage.src = canvasImage;\n shelterImage.style.position = \"absolute\";\n shelterImage.style.top = \"0px\";\n shelterImage.style.left = \"0px\";\n shelterImage.style.right = \"0px\";\n shelterImage.style.bottom = \"0px\";\n canvas.parentNode.appendChild(shelterImage);\n if (typeof callback == \"function\")\n callback(shelterImage);\n }\n}\n\n\n//# sourceURL=webpack://@xtctwins/tctwins-bimx-viewer/./src/BIMXViewer.ts?");
48
48
 
49
49
  /***/ }),
50
50
 
@@ -244,7 +244,7 @@ eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpac
244
244
  \************************************/
245
245
  /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
246
246
 
247
- eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"default\": () => (/* binding */ NavCubeMode)\n/* harmony export */ });\n/* harmony import */ var _xtctwins_tctwins_core__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @xtctwins/tctwins-core */ \"./node_modules/@xtctwins/tctwins-core/dist/tctwins-core.es5.js\");\n/* harmony import */ var _Controller__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../Controller */ \"./src/Controller.ts\");\n\n\n/**\n * 表示导航盒\n * @class\n */\nclass NavCubeMode extends _Controller__WEBPACK_IMPORTED_MODULE_1__[\"default\"] {\n /**\n * 创建一个导航盒对象\n * @param {*} parent\n * @param {*} cfg\n */\n constructor(parent, cfg) {\n super(parent, cfg);\n if (!cfg.navCubeCanvasElement) {\n throw new Error(\"Missing config: NavCubeMode navCubeCanvasElement\");\n }\n const { navCubeCanvasElement } = cfg;\n const { viewerElement } = cfg;\n this._navCube = new _xtctwins_tctwins_core__WEBPACK_IMPORTED_MODULE_0__.NavCubePlugin(this.viewer, {\n canvasElement: navCubeCanvasElement,\n viewerElement,\n fitVisible: false, // 必须设置为false,否则切换视角时包围盒可能更新失效 (除非是模型有多个分布的情况)\n color: \"#CFCFCF\"\n });\n this._navCube.setVisible(this._active);\n this.on(\"active\", (active) => {\n this._navCube.setVisible(active);\n });\n }\n get fitVisible() {\n return this._navCube.getFitVisible();\n }\n /**\n * 开启后,导航盒只会聚焦在显示出来的模型上\n */\n set fitVisible(visible) {\n this._navCube.setFitVisible(visible);\n }\n /**\n * 设置相机视角方向\n * @param areaId\n */\n flyByClick(areaId) {\n this._navCube.flyByClick(areaId);\n }\n destroy() {\n this._navCube.destroy();\n super.destroy();\n }\n}\n\n\n//# sourceURL=webpack://@xtctwins/tctwins-bimx-viewer/./src/toolbar/NavCubeMode.ts?");
247
+ eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"default\": () => (/* binding */ NavCubeMode)\n/* harmony export */ });\n/* harmony import */ var _xtctwins_tctwins_core__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @xtctwins/tctwins-core */ \"./node_modules/@xtctwins/tctwins-core/dist/tctwins-core.es5.js\");\n/* harmony import */ var _Controller__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../Controller */ \"./src/Controller.ts\");\n\n\n/**\n * 表示导航盒\n * @class\n */\nclass NavCubeMode extends _Controller__WEBPACK_IMPORTED_MODULE_1__[\"default\"] {\n /**\n * 创建一个导航盒对象\n * @param {*} parent\n * @param {*} cfg\n */\n constructor(parent, cfg) {\n super(parent, cfg);\n if (!cfg.navCubeCanvasElement) {\n throw new Error(\"Missing config: NavCubeMode navCubeCanvasElement\");\n }\n const { navCubeCanvasElement } = cfg;\n const { viewerElement } = cfg;\n this._navCubeCanvasElement = navCubeCanvasElement;\n this._navCubeCanvasElement.oncontextmenu = (e) => {\n e.preventDefault();\n };\n this._navCube = new _xtctwins_tctwins_core__WEBPACK_IMPORTED_MODULE_0__.NavCubePlugin(this.viewer, {\n canvasElement: navCubeCanvasElement,\n viewerElement,\n fitVisible: false, // 必须设置为false,否则切换视角时包围盒可能更新失效 (除非是模型有多个分布的情况)\n color: \"#CFCFCF\"\n });\n this._navCube.setVisible(this._active);\n this._visible = true;\n this.on(\"active\", (active) => {\n this._navCube.setVisible(active);\n });\n }\n set visible(visible) {\n this._visible = visible;\n if (!!visible) {\n this._navCubeCanvasElement.style.visibility = \"visible\";\n }\n else {\n this._navCubeCanvasElement.style.visibility = \"hidden\";\n }\n }\n get visible() {\n return this._visible;\n }\n get fitVisible() {\n return this._navCube.getFitVisible();\n }\n /**\n * 开启后,导航盒只会聚焦在显示出来的模型上\n */\n set fitVisible(visible) {\n this._navCube.setFitVisible(visible);\n }\n /**\n * 设置相机视角方向\n * @param areaId\n */\n flyByClick(areaId) {\n this._navCube.flyByClick(areaId);\n }\n destroy() {\n this._navCube.destroy();\n super.destroy();\n }\n}\n\n\n//# sourceURL=webpack://@xtctwins/tctwins-bimx-viewer/./src/toolbar/NavCubeMode.ts?");
248
248
 
249
249
  /***/ }),
250
250
 
package/dist/version.d.ts CHANGED
@@ -1,2 +1,2 @@
1
1
 
2
- export const VERSION = "0.1.2";
2
+ export const VERSION = "0.1.3";
package/dist/version.js CHANGED
@@ -1,2 +1,2 @@
1
1
 
2
- export const VERSION = "0.1.2";
2
+ export const VERSION = "0.1.3";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xtctwins/tctwins-bimx-viewer",
3
- "version": "0.1.3",
3
+ "version": "0.1.4",
4
4
  "private": false,
5
5
  "description": "BIM viewer built on xtctwins",
6
6
  "main": "./dist/tctwins-bimx-viewer.min.es.js",
@@ -9,7 +9,7 @@
9
9
  "start": "webpack serve --config webpack.config.js --open",
10
10
  "build": "webpack --config webpack.config.js",
11
11
  "test": "echo \"Error: no test specified\" && exit 1",
12
- "docs": "./node_modules/.bin/esdoc",
12
+ "docs": "esdoc",
13
13
  "lint": "eslint . --ext .js,.jsx,.cjs,.mjs,.ts,.tsx,.cts,.mts --fix --ignore-path .gitignore",
14
14
  "publish": "npm publish --access public",
15
15
  "release": "npm version patch && npm publish --access public"
@@ -25,6 +25,7 @@
25
25
  "author": "tctwins.com",
26
26
  "license": "ISC",
27
27
  "devDependencies": {
28
+ "@xtctwins/tctwins-core": "^1.0.40",
28
29
  "@types/ali-oss": "^6.16.11",
29
30
  "@typescript-eslint/eslint-plugin": "^6.14.0",
30
31
  "@typescript-eslint/parser": "^6.14.0",
@@ -41,11 +42,10 @@
41
42
  "typescript": "^5.4.5",
42
43
  "webpack": "^5.90.1",
43
44
  "webpack-cli": "^5.1.4",
44
- "webpack-dev-server": "^4.15.1"
45
+ "webpack-dev-server": "^4.15.1",
46
+ "ali-oss": "^6.18.1"
45
47
  },
46
48
  "dependencies": {
47
- "@xtctwins/tctwins-core": "^1.0.40",
48
- "ali-oss": "^6.18.1",
49
49
  "axios": "^1.6.5",
50
50
  "bignumber.js": "^9.1.2",
51
51
  "cli": "^1.0.1",
@@ -6,12 +6,16 @@ import Controller from "../Controller";
6
6
  */
7
7
  export default class NavCubeMode extends Controller {
8
8
  protected _navCube: NavCubePlugin;
9
+ protected _navCubeCanvasElement: HTMLCanvasElement;
10
+ protected _visible: boolean;
9
11
  /**
10
12
  * 创建一个导航盒对象
11
13
  * @param {*} parent
12
14
  * @param {*} cfg
13
15
  */
14
16
  constructor(parent: any, cfg: any);
17
+ set visible(visible: boolean);
18
+ get visible(): boolean;
15
19
  get fitVisible(): boolean;
16
20
  /**
17
21
  * 开启后,导航盒只会聚焦在显示出来的模型上