diff --git a/Backend/Views/BuildInfo/_BuildInfo.cshtml b/Backend/Views/BuildInfo/_BuildInfo.cshtml
index 2ec7661..a99c4e6 100644
--- a/Backend/Views/BuildInfo/_BuildInfo.cshtml
+++ b/Backend/Views/BuildInfo/_BuildInfo.cshtml
@@ -1,6 +1,8 @@
diff --git a/Backend/Views/Forge/index.html b/Backend/Views/Forge/index.html
new file mode 100644
index 0000000..6671224
--- /dev/null
+++ b/Backend/Views/Forge/index.html
@@ -0,0 +1,93 @@
+
+
+
+
Autodesk Forge Tutorial
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ @{
+ ViewData["MainNum"] = "1";
+ ViewData["SubNum"] = "4";
+ ViewData["Title"] = "forge管理";
+ }
+
+
+
+
+
+
+
+
+
+
+ Buckets & Objects
+
+
+ New bucket
+
+
+
+ tree here
+
+
+
+
+
+
+
+
+
+
+
+
+
+ For demonstration purposes, objects (files)
+ are NOT automatically translated. After you upload, right click on
+ the object and select "Translate". Note: Technically your bucket name is required to be globally unique across
+ the entire platform - to keep things simple with this tutorial your client ID will be prepended by default to
+ your bucket name and in turn masked by the UI so you only have to make sure your bucket name is unique within
+ your current Forge app.
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Backend/wwwroot/css/forge/main.css b/Backend/wwwroot/css/forge/main.css
new file mode 100644
index 0000000..9bdc22c
--- /dev/null
+++ b/Backend/wwwroot/css/forge/main.css
@@ -0,0 +1,23 @@
+html, body {
+ min-height: 100%;
+ height: 100%;
+}
+
+.fill {
+ height: calc(100vh - 100px);
+}
+
+body {
+ padding-top: 60px; /* space for the top nav bar */
+ margin-right: 30px;
+}
+
+#appBuckets {
+ overflow: auto;
+ width: 100%;
+ height: calc(100vh - 150px);
+}
+
+#forgeViewer {
+ width: 100%;
+}
diff --git a/Backend/wwwroot/forgeDemo.html b/Backend/wwwroot/forgeDemo.html
new file mode 100644
index 0000000..0e8b9fc
--- /dev/null
+++ b/Backend/wwwroot/forgeDemo.html
@@ -0,0 +1,500 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Robot Controls
+
Selected_ID:
+
All_ID:
+
+
電源
+
變更熱點顏色
+
載入熱圖
+
隱藏物件
+
顯示物件
+
透明化物件
+
取消透明物件
+
剖面
+
取得levels
+
匯入設備座標及dbid
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Backend/wwwroot/index.html b/Backend/wwwroot/index.html
new file mode 100644
index 0000000..f97a973
--- /dev/null
+++ b/Backend/wwwroot/index.html
@@ -0,0 +1,88 @@
+
+
+
+
+
Autodesk Forge Tutorial
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Buckets & Objects
+
+
+ New bucket
+
+
+
+ tree here
+
+
+
+
+
+
+
+
+
+
+
+
+
+ For demonstration purposes, objects (files)
+ are NOT automatically translated. After you upload, right click on
+ the object and select "Translate". Note: Technically your bucket name is required to be globally unique across
+ the entire platform - to keep things simple with this tutorial your client ID will be prepended by default to
+ your bucket name and in turn masked by the UI so you only have to make sure your bucket name is unique within
+ your current Forge app.
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Backend/wwwroot/js/forge/ForgeDemo.js b/Backend/wwwroot/js/forge/ForgeDemo.js
new file mode 100644
index 0000000..de1db6d
--- /dev/null
+++ b/Backend/wwwroot/js/forge/ForgeDemo.js
@@ -0,0 +1,1463 @@
+var viewer;
+let fragProxy;
+var targetFloorZ;
+var elevatorSpeed;
+var allDbIdsStr;
+let bulbLight;//點燈
+let spotLight;//聚光燈
+var myDataList;
+var viewableData;
+var dataVizExtn;
+var spriteColorRed;
+var levels;//剖面用
+var baseApiUrl = "http://localhost:3604";
+var instanceTree;
+//var objSendData = { Data: null };
+var tagIdDevList = [];
+
+function launchViewer(urn) {
+ var av = Autodesk.Viewing;
+ var options = {
+ env: 'AutodeskProduction',
+ getAccessToken: getForgeToken
+ };
+
+ Autodesk.Viewing.Initializer(options, () => {
+ viewer = new Autodesk.Viewing.GuiViewer3D(document.getElementById('forgeViewer'));
+ //viewer = new Autodesk.Viewing.Viewer3D(document.getElementById('forgeViewer'));//沒有工具列
+ viewer.start();
+ var documentId = 'urn:' + urn;
+
+ //加入熱點
+ viewer.addEventListener(av.GEOMETRY_LOADED_EVENT, addHotPoint, {
+ once: true,
+ });
+
+ Autodesk.Viewing.Document.load(documentId, onDocumentLoadSuccess, onDocumentLoadFailure);
+
+
+ });
+}
+
+function getAllLeafComponents(viewer, callback) {
+ var cbCount = 0;
+ var tree;
+ var jsData = []
+
+ function getLeafComponentsRec(current, parent) {
+ cbCount++;
+ if (tree.getChildCount(current) != 0) {
+ tree.enumNodeChildren(current, function (children) {
+ getLeafComponentsRec(children, current);
+ }, false);
+ }
+ var nodeName = viewer.model.getInstanceTree().getNodeName(current)
+ jsData.push({ id: current, parent: parent, text: nodeName })
+
+ if (--cbCount == 0) callback(jsData);
+ }
+ viewer.getObjectTree(function (objectTree) {
+ tree = objectTree;
+ var rootId = tree.getRootId()
+ var nodeName = viewer.model.getInstanceTree().getNodeName(rootId)
+ jsData.push({ id: rootId, parent: '#', text: nodeName })
+ var allLeafComponents = getLeafComponentsRec(rootId, '#');
+
+ });
+}
+
+function onDocumentLoadSuccess(doc) {
+ var viewables = doc.getRoot().getDefaultGeometry();
+ viewer.loadDocumentNode(doc, viewables).then(i => {
+ // documented loaded, any action?
+ });
+ viewer.addEventListener(Autodesk.Viewing.AGGREGATE_SELECTION_CHANGED_EVENT, (args) => {
+ var currSelection = viewer.getSelection();
+ var domElem = document.getElementById('id_printer');
+ domElem.innerText = currSelection[0];
+
+
+ //var color = new THREE.Vector4(255 / 255, 0, 0, 1);
+ //viewer.setThemingColor(751, color);
+
+ //var color = new THREE.Vector4(0, 1, 0, 1);
+ //viewer.setThemingColor(751, color);
+
+
+
+ //var dbid = currSelection[0]; //750;
+ //var it = NOP_VIEWER.model.getData().instanceTree;
+ //var indexinNames = it.nodeAccess.dbIdToIndex[dbid];
+ //var indexinStrings = it.nodeAccess.names[indexinNames];
+ //var nodeMainString = it.nodeAccess.strings[indexinStrings];
+ //var nodeSuffixString = it.nodeAccess.nameSuffixes[indexinStrings];
+ //var nodeFinalName = it.getNodeName(dbid);
+ //console.log("names: " + indexinNames + ", inStrings: " + indexinStrings + ", nodeMainString: " + nodeMainString + ", nodeSuffix: " + nodeSuffixString);
+ //console.log("nodeFinalName: " + nodeFinalName);
+
+ //var vp = viewer.impl.clientToViewport(event.canvasX, event.canvasY);
+ //var renderer = viewer.impl.renderer();
+
+ //var dbId = renderer.idAtPixel(vp.x, vp.y);
+ //if (dbId) {
+ // console.debug("Selected Id: " + dbId);
+ // //viewer.select(dbId);
+ // //viewer.impl.invalidate(true);
+ // viewer.model.getExternalIdMapping(data => console.log(data));
+ //}
+
+ //set color
+ //let nodeIdObj = 750;
+ //this.viewer.setThemingColor(nodeIdObj, red, this.model);
+
+ //const color = new THREE.Vector4(1.0, 0.0, 0.0, 0.5);
+ //viewer.setThemingColor(751, color, null, true);
+
+ var myDbid = currSelection;
+ //viewer.getProperties(myDbid, function (e) {
+ // //console.log('Entire object response ', e);
+ // //console.log('Properties ', e.properties);
+ // //foreach(item in e.properties) {
+ // // if (item.displayName == "【tag_id】") {
+ // // console.log(">> " + item.displayValue);
+ // // }
+ // //}
+
+ // e.properties.forEach(function (item) {
+ // //if (item.displayName == "【tag_id】") {
+ // // console.log(">> " + item.displayValue);
+ // //}
+ // if (item.displayName == "tag_id") {
+ // console.log(">> " + item.displayValue);
+ // }
+ // });
+
+ //});
+
+ });
+
+ //viewer.loadExtension('ToolbarExtension');
+
+
+ viewer.addEventListener(Autodesk.Viewing.GEOMETRY_LOADED_EVENT, function () {
+ instanceTree = viewer.model.getData().instanceTree;
+
+ var domElem = document.getElementById('all_id');
+ allDbIdsStr = Object.keys(instanceTree.nodeAccess.dbIdToIndex);
+ domElem.innerText = allDbIdsStr;
+
+ //parseInt(allDbIdsStr[i]
+ //for (var i = 0; i < allDbIdsStr.length; i++) {
+ // //setTransparency(parseInt(allDbIdsStr[i]), 0.2);
+ // viewer.getProperties(parseInt(allDbIdsStr[i], function (e) {
+ // e.properties.forEach(function (item) {
+ // //if (item.displayName == "【tag_id】") {
+ // // console.log(">> " + item.displayValue);
+ // //}
+ // if (item.displayName == "tag_id") {
+ // console.log(">> " + item.displayValue);
+ // }
+ // });
+
+ // })
+ //}
+
+ // ------------------ 取得tag_id底下的nodeId --------------------------------------
+ var curDbId = 0;
+ var tagId = 0;
+ var _parentId = 0;
+ var _childId = 0;
+ var itemName = '';
+ var childIdArr = new Array();
+ let evelMap = new Map();
+
+ let tree = viewer.model.getData().instanceTree;
+ const model = viewer.model;
+ const fragList = model.getFragmentList();
+
+
+ loadHeatmaps(model);
+
+
+
+ //allDbIdsStr.forEach((dbId) => {
+ // curDbId = parseInt(dbId);
+ // viewer.getProperties(curDbId, function (e) {
+ // e.properties.forEach(function (item) {
+ // if (item.displayName == "tag_id" && e.name == "【電梯】") {
+
+ // //getFragmentWorldMatrixByNodeId(e.dbId, viewer);
+ // //let fragProxy = viewer.impl.getFragmentProxy(viewer.model, frag);
+
+ // tree.enumNodeFragments(e.dbId, function (frag) {
+
+ // let fragProxy = viewer.impl.getFragmentProxy(viewer.model, frag);
+ // let matrix = new THREE.Matrix4();
+ // console.log("proxy: " + fragProxy.position);
+
+ // fragProxy.getWorldMatrix(matrix);
+
+ // });
+
+
+
+ // tagId = e.dbId;
+ // viewer.getProperties(tagId, function (e2) {
+ // e2.properties.forEach(function (item2) {
+ // if (item2.displayName == "child") {
+ // _parentId = item2.displayValue;
+
+ // viewer.getProperties(_parentId, function (e3) {
+ // let itemMap = new Map();
+ // e3.properties.forEach(function (item3) {
+ // if (item3.displayName == "child") {
+ // _childId = item3.displayValue;
+ // childIdArr.push(_childId);
+
+ // var n = 0;
+ // viewer.getProperties(childIdArr[n], function (e5) {
+ // e5.properties.forEach(function (item5) {
+ // if (item5.displayName == "Name") {
+ // itemName = item5.displayValue;
+ // itemMap.set(childIdArr[0], itemName)
+ // console.log("childIdArr[0] ", childIdArr[0])
+ // console.log("item name: ", itemName);
+ // n += 3;
+ // }
+ // });
+ // })
+
+ // n = 1;
+ // viewer.getProperties(childIdArr[n], function (e6) {
+ // e6.properties.forEach(function (item6) {
+ // if (item6.displayName == "Name") {
+ // itemName = item6.displayValue;
+ // itemMap.set(childIdArr[1], itemName)
+ // console.log("childIdArr[1] ", childIdArr[1])
+ // console.log("item name: ", itemName);
+ // n += 3;
+ // }
+ // });
+ // })
+
+ // n = 2;
+ // viewer.getProperties(childIdArr[n], function (e7) {
+ // e7.properties.forEach(function (item7) {
+ // if (item7.displayName == "Name") {
+ // itemName = item7.displayValue;
+ // itemMap.set(childIdArr[2], itemName)
+ // console.log("childIdArr[2] ", childIdArr[2])
+ // console.log("item name: ", itemName);
+ // n += 3;
+ // }
+ // });
+ // })
+
+ // }
+ // });
+ // evelMap.set(item.displayValue, itemMap)
+ // })
+
+ // }
+ // });
+ // })
+ // }
+ // });
+
+ // })
+
+ //})
+
+ allDbIdsStr.forEach((dbId) => {
+ curDbId = parseInt(dbId);
+ viewer.getProperties(curDbId, function (e) {
+ e.properties.forEach(function (item) {
+ if (item.displayName == "【tag_id】") { // Tag_name tag_id 【tag_id】
+ if (item.displayValue != "") {
+ //if ((item.displayValue).indexOf('TPE_B1_ME_M10') > -1) {
+ console.log("--------------------------------------------------");
+ console.log("Tag_name dbid: " + e.dbId);
+ console.log("value: " + item.displayValue);
+
+ //myDataList.forEach((myData, index) => {
+ // devices.push({ id: index, position: JSON.parse(myData.device_coordinate_3d), sensorTypes: ["temperature", "humidity"] });
+ //});
+ //}
+
+ let bounds = new THREE.Box3();
+
+ instanceTree.enumNodeFragments(e.dbId, (fragId) => {
+ let box = new THREE.Box3();
+ fragList.getWorldBounds(fragId, box);
+ bounds.union(box);
+ }, true);
+ var position = bounds.center();
+ //if ((item.displayValue).indexOf('TPE_B1_ME_M10') > -1) {
+ console.log("position: (" + (position.x).toFixed(2) + ", " + (position.y).toFixed(2) + ", " + (position.z).toFixed(2) + ")");
+ tagIdDevList.push({ device_number: item.displayValue, device_coordinate_3d: '{ "x": ' + (position.x).toFixed(2) + ', "y": ' + (position.y).toFixed(2) + ', "z": ' + (position.z).toFixed(2) + ' }', forge_dbid: e.dbId });
+ console.log("--------------------------------------------------");
+ //}
+ }
+ //getFragmentWorldMatrixByNodeId(e.dbId, viewer);
+ //let fragProxy = viewer.impl.getFragmentProxy(viewer.model, frag);
+
+
+ }
+ });
+
+ })
+
+ })
+
+ //---------------------- end ---------------------------------------------------
+
+
+
+ //var curDbId = 0;
+ //var tagId = 0;
+ //var _parentId = 0;
+ //var _childId = 0;
+ ////var childIdArr = new Array();
+ //let evelMap = new Map();
+
+ //allDbIdsStr.forEach((dbId) => {
+ // curDbId = parseInt(dbId);
+ // viewer.getProperties(curDbId, function (e) {
+ // e.properties.forEach(function (item) {
+ // if (item.displayName == "tag_id" && e.name == "【電梯】") {
+
+ // tagId = e.dbId;
+ // viewer.getProperties(tagId, function (e2) {
+ // e2.properties.forEach(function (item2) {
+ // if (item2.displayName == "child") {
+ // _parentId = item2.displayValue;
+
+ // viewer.getProperties(_parentId, function (e3) {
+ // var childIdArr = new Array();
+
+ // e3.properties.forEach(function (item3) {
+ // if (item3.displayName == "child") {
+ // _childId = item3.displayValue;
+ // childIdArr.push(_childId);
+ // }
+ // });
+ // evelMap.set(item.displayValue, childIdArr)
+ // console.log("map: " + evelMap);
+ // })
+
+ // }
+ // });
+ // })
+ // }
+ // });
+
+ // })
+
+ //})
+
+
+ //let tree = viewer.model.getData().instanceTree;
+ let nodeId = 12112;//12104; //749; //10952;
+ let nodeId2 = 12111;//12105; //750;
+ let nodeId3 = 12110;//12104; //751;
+
+ tree.enumNodeFragments(nodeId, function (frag) {
+ fragProxy = viewer.impl.getFragmentProxy(viewer.model, frag);
+ fragProxy.getAnimTransform();
+ let fragPosition = new THREE.Vector3(0, 0, 0);// 一樓0 二樓15 三樓 26
+
+ fragProxy.position = fragPosition
+
+ fragProxy.updateAnimTransform()
+
+ });
+ viewer.impl.sceneUpdated(true);
+
+ //------------ add -------------
+ tree.enumNodeFragments(nodeId2, function (frag) {
+ fragProxy = viewer.impl.getFragmentProxy(viewer.model, frag);
+ fragProxy.getAnimTransform();
+ let fragPosition = new THREE.Vector3(0, 0, 0);// 一樓0 二樓15 三樓 26
+
+ fragProxy.position = fragPosition
+
+ fragProxy.updateAnimTransform()
+
+ });
+ viewer.impl.sceneUpdated(true);
+
+ tree.enumNodeFragments(nodeId3, function (frag) {
+ fragProxy = viewer.impl.getFragmentProxy(viewer.model, frag);
+ fragProxy.getAnimTransform();
+ let fragPosition = new THREE.Vector3(0, 0, 0);// 一樓0 二樓15 三樓 26
+
+ fragProxy.position = fragPosition
+
+ fragProxy.updateAnimTransform()
+
+ });
+ viewer.impl.sceneUpdated(true);
+
+ });
+
+ //add toolbar fail
+ //function ToolbarExtension(viewer, options) {
+ // Autodesk.Viewing.Extension.call(this, viewer, options);
+ //}
+
+ //ToolbarExtension.prototype = Object.create(Autodesk.Viewing.Extension.prototype);
+ //ToolbarExtension.prototype.constructor = ToolbarExtension;
+
+ //ToolbarExtension.prototype.load = function () {
+ // this.viewer.setLightPreset(6);
+ // this.viewer.setEnvMapBackground(true);
+ // this.viewer.fitToView();
+ // return true;
+ //};
+
+ //ToolbarExtension.prototype.unload = function () {
+
+ //};
+ //Autodesk.Viewing.theExtensionManager.registerExtension('ToolbarExtension', ToolbarExtension);
+
+ //ToolbarExtension.prototype.onToolbarCreated = function (toolbar) {
+ // //alert('TODO: customize Viewer toolbar');
+
+ // var viewer = this.viewer;
+ // var button1 = new Autodesk.Viewing.UI.Button('show-env-bg-button');
+ // button1.onClick = function (e) {
+ // viewer.setEnvMapBackground(true);
+ // };
+ // button1.addClass('show-env-bg-button');
+ // button1.setToolTip('Show Environment');
+
+ // //SubToolbar
+ // this.subToolbar = new Autodesk.Viewing.UI.ControlGroup('my-custom-toolbar');
+ // this.subToolbar.addControl(button1);
+ // toolbar.addControl(this.subToolbar);
+
+ //};
+
+
+ //加入點燈光
+ //bulbLight = new THREE.PointLight(0xffffff, 1, 1, 2);//0xff0000
+ //bulbLight.position.set(-17.33, 51.03, -2.52);//17.880840301513672
+ //bulbLight.castShadow = true;
+ //bulbLight.intensity = 50;
+ //bulbLight.distance = 1;
+ //bulbLight.emissiveIntensity = bulbLight.intensity / Math.pow(0.02, 2.0);
+ //viewer.scene.add(bulbLight);
+
+ //聚光燈
+ //spotLight = new THREE.SpotLight(0xffff00, 80, 10);//0xffffff
+ //spotLight.position.set(-7.58, 18.20, -0.25); //set(-17.33, 51.03, -2.52);
+ //spotLight.castShadow = true;
+ //spotLight.visible = true;
+ //var geom = new THREE.BoxGeometry(); //create 幾何對象 -17.33, 51.03, -4.52
+ //var material = new THREE.MeshLambertMaterial({ color: 0xffff00 });//0xff0000
+ //var cube = new THREE.Mesh(geom, material);
+ //cube.position.set(-7.58, 18.20, -1); //set(-17.33, 51.03, -10);//-4.52
+ //viewer.scene.add(cube);
+ //spotLight.target = cube;
+ //viewer.scene.add(spotLight);
+
+}
+
+//------------------- 加入熱點 -----------------
+async function addHotPoint(data) {
+ var viewer = data.target;
+ dataVizExtn = await viewer.loadExtension("Autodesk.DataVisualization");
+ const DataVizCore = Autodesk.DataVisualization.Core;
+ const viewableType = Autodesk.DataVisualization.Core.ViewableType.SPRITE;//DataVizCore.ViewableType.SPRITE;
+ const spriteColor = new THREE.Color(0xffff00); //0xffffff
+ spriteColorRed = new THREE.Color(0xff0000);
+ const spriteIcon = "https://d2zqnmauvnpnnm.cloudfront.net/assets-1/images/circle.svg"; //"/img/forge/hotspot.svg";
+
+ const style = new DataVizCore.ViewableStyle(viewableType, spriteColor, spriteIcon);
+
+
+ //function onSpriteClicked(event) {
+ // console.log(`Sprite clicked: ${event.dbId}`);
+ //}
+
+ //熱點 點擊事件註冊
+ viewer.addEventListener(DataVizCore.MOUSE_CLICK, onSpriteClicked);//MOUSE_CLICK SPRITE_SELECTED
+ //viewer.addEventListener(DataVizCore.MOUSE_CLICK_OUT, onSpriteClickedOut);
+ //viewer.addEventListener(DataVizCore.MOUSE_DOWN, onSpriteClicked);
+ //viewer.addEventListener(DataVizCore.MOUSE_HOVERING, onSpriteHovering);
+
+ viewer.addEventListener(
+ Autodesk.Viewing.SELECTION_CHANGED_EVENT,
+ onSelectionChange
+ );
+
+ viewableData = new DataVizCore.ViewableData();
+ viewableData.spriteSize = 24; // Sprites as points of size 24 x 24 pixels
+
+ //熱圖 打點 x: 0, y: 25.03, z: -2.52 三菱
+ myDataList = [{ position: { x: -21.95, y: 8.92, z: 63.27 } }, //-21.95, 8.92, 63.27
+ { position: { x: -21.95, y: 7.61, z: 63.27 } },//-21.95, 7.61, 63.27
+ { position: { x: -21.95, y: 6.43, z: 63.27 } },//-21.95, 6.43, 63.27
+ { position: { x: -21.95, y: 5.31, z: 63.27 } }//-21.95, 5.31, 63.27
+ ];// x: -17.33, y: 51.03, z: -2.52 ; x: -23.21, y: 51.03, z: -2.52
+
+ myDataList.forEach((myData, index) => {
+ const dbId = 10 + index;
+ const myPosition = myData.position;
+ const viewable = new DataVizCore.SpriteViewable(myPosition, style, dbId);
+
+ viewableData.addViewable(viewable);
+ });
+
+ await viewableData.finish();
+ dataVizExtn.addViewables(viewableData);
+
+ //---------------- 熱點點擊事件 --------------------
+ function onSpriteClicked(event) {
+ event.hasStopped = true;
+ if (event != undefined && event != null) {
+ if (event.dbId >= 10 && event.dbId <= 13) {//event.dbId > 0 && event.dbId < 19
+ console.log(`Sprite clicked: ${event.dbId}`);
+ openHotspotModal();
+ }
+
+ if (event.clickInfo != null) {
+ //if (event.clickInfo.dbId == 12449) {
+ //const viewablesToUpdate = [event.dbId];
+ //dataVizExtn.invalidateViewables(viewablesToUpdate, (viewable) => {
+ // return {
+ // color: spriteColorRed,
+ // };
+ //});
+ //}
+
+
+ //document.getElementById('lbltipAddedComment').innerHTML .toFixed(2);
+ document.getElementById('deviceName').innerHTML = viewer.model.getInstanceTree().getNodeName(event.clickInfo.dbId);
+ document.getElementById('deviceDbid').innerHTML = event.clickInfo.dbId;
+ document.getElementById('devicePosition').innerHTML = "(" + (event.clickInfo.point.x).toFixed(2) + ", " + (event.clickInfo.point.y).toFixed(2) + ", " + (event.clickInfo.point.z).toFixed(2) + ")";
+ console.log(`event>> dbId: ${event.clickInfo.dbId}, id: ${event.clickInfo.object.id}, position.x: ${event.clickInfo.point.x}, y: ${event.clickInfo.point.y}, z: ${event.clickInfo.point.z}, name: ${viewer.model.getInstanceTree().getNodeName(event.clickInfo.dbId)}`);
+ }
+ }
+ }
+
+ //function onSpriteClickedOut(event) {
+ // //const dataVizExtn = await viewer.loadExtension("Autodesk.DataVisualization");
+ // event.hasStopped = true;
+
+ // const viewablesToUpdate = [event.dbId];
+ //dataVizExtn.invalidateViewables(viewablesToUpdate, (viewable) => {
+ // return {
+ // scale: 1.0, // Restore the viewable size
+ // //url: "https://.../circle.svg",
+ // };
+ //});
+ //}
+
+ //function onSpriteHovering(event) {
+ // const targetDbId = event.dbId;
+
+ // if (event != undefined && event != null && event.hovering) {
+
+ // if (targetDbId >= 10 && targetDbId <= 13) {//event.dbId > 0 && event.dbId < 19
+ // console.log(`Sprite clicked: ${event.dbId}`);
+ // openHotspotModal();
+ // }
+
+ // console.log(`The mouse hovers over ${targetDbId}`);
+ // } else {
+ // console.log(`The mouse hovers off ${targetDbId}`);
+ // }
+ //}
+}
+//------------------- end --------------
+
+// 熱點 更換顏色
+function changeColorForHotspot(dbId) {
+ //const viewablesToUpdate = [event.dbId];
+ const viewablesToUpdate = dbId;
+ dataVizExtn.invalidateViewables(viewablesToUpdate, (viewable) => {
+ return {
+ color: spriteColorRed,
+ };
+ });
+}
+
+
+////---------------- 熱點點擊事件 --------------------
+//function onSpriteClicked(event) {
+// //event.hasStopped = true;
+// if (event != undefined && event != null) {
+// if (event.dbId >= 10 && event.dbId <= 13) {//event.dbId > 0 && event.dbId < 19
+// console.log(`Sprite clicked: ${event.dbId}`);
+// //alert("I am an alert box! " + event.dbId);
+// openHotspotModal();
+// }
+
+// if (event.clickInfo != null) {
+// //document.getElementById('lbltipAddedComment').innerHTML .toFixed(2);
+// document.getElementById('deviceName').innerHTML = viewer.model.getInstanceTree().getNodeName(event.clickInfo.dbId);
+// document.getElementById('deviceDbid').innerHTML = event.clickInfo.dbId;
+// document.getElementById('devicePosition').innerHTML = "(" + (event.clickInfo.point.x).toFixed(2) + ", " + (event.clickInfo.point.y).toFixed(2) + ", " + (event.clickInfo.point.z).toFixed(2) + ")";
+// console.log(`event>> dbId: ${event.clickInfo.dbId}, id: ${event.clickInfo.object.id}, position.x: ${event.clickInfo.point.x}, y: ${event.clickInfo.point.y}, z: ${event.clickInfo.point.z}, name: ${viewer.model.getInstanceTree().getNodeName(event.clickInfo.dbId)}`);
+// }
+// }
+//}
+
+//function onSpriteClickedOut(event) {
+// //const dataVizExtn = await viewer.loadExtension("Autodesk.DataVisualization");
+// event.hasStopped = true;
+
+// const viewablesToUpdate = [event.dbId];
+// dataVizExtn.invalidateViewables(viewablesToUpdate, (viewable) => {
+// return {
+// scale: 1.0, // Restore the viewable size
+// url: "https://.../circle.svg",
+// };
+// });
+
+// // Continue with application logic that reacts to the deselection
+// // event (e.g., update UI to a state where no selection is made).
+//}
+
+function onSelectionChange(event) {
+ if (event != undefined && event != null) {
+ const dbIds = event.dbIdArray;
+
+ if (dbIds.length > 0) {
+ // 處理已選取元件的邏輯
+
+ //openHotspotModal();
+ console.log(`------ name: ${viewer.model.getInstanceTree().getNodeName(dbIds)} , dbId: ${dbIds}`);//, id: ${event.clickInfo.object.id}, position.x: ${event.clickInfo.point.x}, y: ${event.clickInfo.point.y}, z: ${event.clickInfo.point.z}
+ } else {
+ // 處理沒有選取元件的邏輯
+ console.log("no item");
+ }
+ }
+}
+//---------------- end -----------------------------
+
+//----------------- 開關熱點小視窗 ----------------------
+function openHotspotModal() {
+ var modal = document.getElementById("hotspotModal");
+ modal.style.display = "block";
+ $("#pills-register-tab").removeClass("active");
+ $("#pills-alarm-tab").removeClass("active");
+ $("#pills-operation-tab").removeClass("active");
+ $("#pills-login-tab").tab("show");
+}
+
+function closeHotspotModal() {
+ var modal = document.getElementById("hotspotModal");
+ modal.style.display = "none";
+ //dataVizExtn.removeAllViewables();
+
+}
+//------------------ end --------------------------------
+
+//-------------- 更改燈光範圍 --------------------------
+function setLightPower(value) {
+ //bulbLight.intensity = (value * 10);
+ //bulbLight.distance = value;
+ viewer.impl.sceneUpdated(true);
+}
+
+function setLightOpenOrClose(value) {
+ if (value)
+ spotLight.visible = true;
+ else {
+ spotLight.visible = false;
+ }
+ viewer.impl.sceneUpdated(true);
+}
+
+function setLightTransparency(value) {
+ bulbLight.intensity = (value * 10);
+ //bulbLight.
+ viewer.impl.sceneUpdated(true);
+}
+//------------- end -----------------------------------
+
+
+//function getPosition(nodeId) {
+function getFragmentWorldMatrixByNodeId(nodeId, viewer) {
+ let tree = viewer.model.getData().instanceTree;
+ let result = {
+ fragId: [],
+ matrix: [],
+ };
+ //let viewer = this.viewer;
+ tree.enumNodeFragments(nodeId, function (frag) {
+
+ let fragProxy = viewer.impl.getFragmentProxy(viewer.model, frag);
+ let matrix = new THREE.Matrix4();
+
+ fragProxy.getWorldMatrix(matrix);
+
+ result.fragId.push(frag);
+ result.matrix.push(matrix);
+ });
+ console.log("position: " + result);
+ return result;
+}
+//}
+
+function setTransparentBuilding() {
+ //allDbIdsStr.forEach((dbId) => {
+ // setTransparency(dbId, 0.2);
+ //})
+
+ for (var i = 0; i < allDbIdsStr.length; i++) {
+ setTransparency(parseInt(allDbIdsStr[i]), 0);
+ }
+
+}
+
+function recoverTransparentBuilding() {
+ //allDbIdsStr.forEach((dbId) => {
+ // setTransparency(dbId, 1);
+ //})
+
+ for (var i = 0; i < allDbIdsStr.length; i++) {
+ setTransparency(parseInt(allDbIdsStr[i]), 1);
+ }
+}
+
+//設定模型 透明度
+function setTransparency(nodeId, opacity) {
+ var model = viewer.model;
+ //var nodeId = 1633;
+
+ var fragList = viewer.model.getFragmentList();
+
+ var fragIds = []
+
+ model.getData().instanceTree.enumNodeFragments(
+ nodeId, (fragId) => {
+ fragIds.push(fragId)
+ });
+
+ fragIds.forEach((fragId) => {
+ //获取材质
+ var material = fragList.getMaterial(fragId);
+
+ if (material) {
+ //设置透明度
+ material.opacity = opacity;//0.5;
+ material.transparent = true;
+ //标记更新
+ material.needsUpdate = true;
+ }
+ })
+
+ //更新viewer
+ viewer.impl.invalidate(true, true, true);
+}
+
+
+
+function setElevatorFloor(floor) {
+ if (floor == 0)
+ targetFloorZ = 0;
+ else if (floor == 1)
+ targetFloorZ = 14.6;// 15;
+ else if (floor == 2)
+ targetFloorZ = 24.6;// 26;
+ else if (floor == 3)
+ targetFloorZ = 34.6;
+ else if (floor == 4)
+ targetFloorZ = 44.6;
+ else if (floor == 5)
+ targetFloorZ = 54.6;
+ else if (floor == 6)
+ targetFloorZ = 64.6;
+ else if (floor == 7)
+ targetFloorZ = 74.6;
+ else if (floor == 8)
+ targetFloorZ = 84.6;
+ else if (floor == 9)
+ targetFloorZ = 94.6;
+ else if (floor == 10)
+ targetFloorZ = 104.6;
+ else if (floor == 11)
+ targetFloorZ = 114.6;
+ else if (floor == 12)
+ targetFloorZ = 124.6;
+ else if (floor == -1)
+ targetFloorZ = -13;
+}
+
+function setElevatorSpeed(speed) { //0.01 ~ 1
+ elevatorSpeed = speed;
+}
+
+function movElevator() {
+
+
+ let tree = viewer.model.getData().instanceTree;//三組:(749,750,751),(755,756,757),(761,762,763)
+ let nodeId = 12112;//12104; //749; //10952;
+ let nodeId2 = 12111;//12105; //750;
+ let nodeId3 = 12110;//12104; //751;
+ let fragProxyZ = 0;
+ var movStatus = 0; // 0=no 1=up 2=down
+ changeColor(nodeId3);
+ //setTransparency(0.2);
+ setTransparentBuilding();
+
+
+ if (fragProxy.position.z > targetFloorZ) {
+ movStatus = 2
+ }
+ else if (fragProxy.position.z < targetFloorZ) {
+ movStatus = 1
+ }
+
+ if (movStatus == 0) {
+ return;
+ }
+
+ tree.enumNodeFragments(nodeId, function (frag) {
+ fragProxy = viewer.impl.getFragmentProxy(viewer.model, frag);
+ fragProxy.getAnimTransform();
+ //let fragPosition = new THREE.Vector3(0, 0, 15);// 一樓0 二樓15 三樓 26
+ if (movStatus == 2) {
+ fragProxy.position.z -= elevatorSpeed;
+ }
+ else if (movStatus == 1) {
+ fragProxy.position.z += elevatorSpeed;
+ }
+
+ fragProxyZ = fragProxy.position.z;
+ fragProxy.updateAnimTransform()
+
+ });
+ viewer.impl.sceneUpdated(true);
+
+ tree.enumNodeFragments(nodeId2, function (frag) {
+ fragProxy = viewer.impl.getFragmentProxy(viewer.model, frag);
+ fragProxy.getAnimTransform();
+ //let fragPosition = new THREE.Vector3(0, 0, 15);// 一樓0 二樓15 三樓 26
+ if (movStatus == 2) {
+ fragProxy.position.z -= elevatorSpeed;
+ }
+ else if (movStatus == 1) {
+ fragProxy.position.z += elevatorSpeed;
+ }
+
+ fragProxyZ = fragProxy.position.z;
+ fragProxy.updateAnimTransform()
+
+ });
+ viewer.impl.sceneUpdated(true);
+
+ tree.enumNodeFragments(nodeId3, function (frag) {
+ fragProxy = viewer.impl.getFragmentProxy(viewer.model, frag);
+ fragProxy.getAnimTransform();
+ //let fragPosition = new THREE.Vector3(0, 0, 15);// 一樓0 二樓15 三樓 26
+ if (movStatus == 2) {
+ fragProxy.position.z -= elevatorSpeed;
+ }
+ else if (movStatus == 1) {
+ fragProxy.position.z += elevatorSpeed;
+ }
+
+ fragProxyZ = fragProxy.position.z;
+ fragProxy.updateAnimTransform()
+
+ });
+ viewer.impl.sceneUpdated(true);
+
+ if (movStatus == 2) {
+ if (fragProxyZ >= targetFloorZ) {
+ requestAnimationFrame(movElevator);
+ }
+ else {
+ hideColor(nodeId3);
+ //setTransparency(1);
+ recoverTransparentBuilding();
+ }
+ }
+ else if (movStatus == 1) {
+ if (fragProxyZ <= targetFloorZ) {
+ requestAnimationFrame(movElevator);
+ }
+ else {
+ hideColor(nodeId3);
+ //setTransparency(1);
+ recoverTransparentBuilding();
+ }
+ }
+
+
+ //let fragPosition = new THREE.Vector3(position);// 一樓0 二樓15 三樓 26
+
+ //fragProxy.position = fragPosition;
+
+ //fragProxy.updateAnimTransform();
+
+ //viewer.impl.sceneUpdated(true);
+}
+
+function changeColor(nodeId) {//電梯變綠色
+ var color = new THREE.Vector4(0, 1, 0, 1);
+ viewer.setThemingColor(nodeId, color);
+}
+
+function hideColor(nodeId) {//顏色改成透明
+ var color = new THREE.Vector4(0, 1, 0, 0);
+ viewer.setThemingColor(nodeId, color);
+}
+
+//function movElevator() {
+
+
+// let tree = viewer.model.getData().instanceTree;
+// let nodeId = 750;// 10952;
+// let fragProxyZ = 0;
+// var movStatus = 0; // 0=no 1=up 2=down
+
+
+// if (fragProxy.position.z > targetFloorZ) {
+// movStatus = 2
+// }
+// else if (fragProxy.position.z < targetFloorZ) {
+// movStatus = 1
+// }
+
+// if (movStatus == 0) {
+// return;
+// }
+
+// tree.enumNodeFragments(nodeId, function (frag) {
+// fragProxy = viewer.impl.getFragmentProxy(viewer.model, frag);
+// fragProxy.getAnimTransform();
+// //let fragPosition = new THREE.Vector3(0, 0, 15);// 一樓0 二樓15 三樓 26
+// if (movStatus == 2) {
+// fragProxy.position.z -= elevatorSpeed;
+// }
+// else if (movStatus == 1) {
+// fragProxy.position.z += elevatorSpeed;
+// }
+
+// fragProxyZ = fragProxy.position.z;
+// fragProxy.updateAnimTransform()
+
+// });
+// viewer.impl.sceneUpdated(true);
+
+// if (movStatus == 2) {
+// if (fragProxyZ >= targetFloorZ) {
+// requestAnimationFrame(movElevator);
+// }
+// }
+// else if (movStatus == 1) {
+// if (fragProxyZ <= targetFloorZ) {
+// requestAnimationFrame(movElevator);
+// }
+// }
+
+
+// //let fragPosition = new THREE.Vector3(position);// 一樓0 二樓15 三樓 26
+
+// //fragProxy.position = fragPosition;
+
+// //fragProxy.updateAnimTransform();
+
+// //viewer.impl.sceneUpdated(true);
+//}
+
+function getAllDbIds(viewer) {
+ var instanceTree = viewer.model.getData().instanceTree;
+
+ var allDbIdsStr = Object.keys(instanceTree.nodeAccess.dbIdToIndex);
+
+ return allDbIdsStr.map(function (id) { return parseInt(id) });
+}
+
+//釋放viewer
+function ReleaseViewer() {
+ viewer.finish();
+ viewer = null;
+ Autodesk.Viewing.shutdown();
+}
+
+//擴展類 刪除添加的所有DOM元素和事件
+//ToolbarExtension.prototype.unload = function () {
+// if (this.subToolbar) {
+// this.viewer.toolbar.removeControl(this.subToolbar);
+// this.subToolbar = null;
+// }
+//};
+
+
+// ---- 模型剖面 ----
+function getCutPlaneParam(idx, n) {
+ if (idx < 0 || !n) return;
+
+ const level = this.levels[idx];
+ if (!level) return;
+
+ //const precision = Autodesk.Viewing.Private.calculatePrecision( level.elevation );
+ const model = this.viewer.model;
+ const globalOffset = model.getData().globalOffset;
+ const units = model.getUnitString();
+ const elevRaw = Autodesk.Viewing.Private.convertUnits('ft', units, 1, level.elevation);
+
+ let d = elevRaw - globalOffset.z - 0.5;
+ if (n == 1)
+ d = -1 * d;
+
+ return new THREE.Vector4(0, 0, n, d);
+}
+
+function onButtonClicked() {
+ const upperSelector = document.getElementById('adn-upper-lvl-selector');
+ const lowerSelector = document.getElementById('adn-lower-lvl-selector');
+
+ if (!upperSelector || !lowerSelector)
+ return;
+
+ const upperIdx = upperSelector.selectedIndex;
+ const upperCutPlaneParam = this.getCutPlaneParam(upperIdx, 1);
+ const lowerIdx = lowerSelector.selectedIndex;
+ const lowerCutPlaneParam = this.getCutPlaneParam(lowerIdx, -1);
+
+ this.viewer.setCutPlanes([upperCutPlaneParam, lowerCutPlaneParam]);
+}
+
+function displayCuttedPlane() {
+
+}
+
+/**
+ * Autodesk.Viewing.Document.load() failuire callback.
+ */
+function onDocumentLoadFailure(viewerErrorCode) {
+ console.error("onDocumentLoadFailure() - errorCode:" + viewerErrorCode);
+}
+
+function getForgeToken(callback) {
+ // for 三菱
+ fetch('/api/forge/oauth/token').then(res => {
+ res.json().then(data => {
+ callback(data.dictionary.access_token, data.dictionary.expires_in);
+ });
+ });
+
+ //for wsp get token
+ //var wspApiUrl = "https://quick-sonar-302302.de.r.appspot.com";
+ //fetch(wspApiUrl + '/api/forge/getToken').then(res => {
+ // res.json().then(data => {
+ // callback(data.access_token, data.expires_in);
+ // });
+ //});
+
+ //callback("eyJhbGciOiJSUzI1NiIsImtpZCI6IlU3c0dGRldUTzlBekNhSzBqZURRM2dQZXBURVdWN2VhIn0.eyJzY29wZSI6WyJkYXRhOnJlYWQiXSwiY2xpZW50X2lkIjoib0FoWVJBZkpvUkFRVFFqZmtBdExRSGkwYTIyc2pwSEoiLCJhdWQiOiJodHRwczovL2F1dG9kZXNrLmNvbS9hdWQvYWp3dGV4cDYwIiwianRpIjoiMm1EZ25yN0puYnhNUU91d2h2Y0lhTlZTOTIxOU9WMDlLZkZIRmhpa3BuMTUwbUNVbmRsVU9ZazdCMWxURXA4QiIsImV4cCI6MTY3MDk4NjgwM30.EfXtO7rdW25_WFxcFdYA-yWMUnRenuWc8MtvrM3i92jJU1_gZ7L1GJCLTH1MRJqnxp9X-oO4NToq1kt2sbUYWgwUPd3BvJwckr55s9hagy-0WENfUfEgX1csnrrKpnnbmlHIGQBgsUTklRRXleW6A63A0XkVH0GvJFv4h7K6-4gAi21SLhE_GwmbTWXSOxuoDnluIAVEDEf0ZmUYgnb4nImujScz876e4A0PagW0yf9-RSqmzNUctsasP6MBzLQxOHMd97jQvBDCFEzQqGgpbSTyc43Gdhy2wQM9sSxc_vR3ZvzJPm_78uda0HjH9M8B9SjwY07XHHdhGmbH-1FBQw", 3599);
+}
+
+async function loadHeatmaps(model) {
+
+ const dataVizExtn = await viewer.loadExtension("Autodesk.DataVisualization");
+
+ // Given a model loaded from Forge
+ const structureInfo = new Autodesk.DataVisualization.Core.ModelStructureInfo(model);
+
+ //x: -17.33, y: 51.03, z: -2.52
+ const devices = [
+ {
+ id: "Oficina 3",
+ //name: "Oficina-",
+ position: { x: 6.98, y: -19.00, z: 16.86 }, // x: 0, y: 25, z: -2.5 (-4.93, -20.61, 16.86)
+ sensorTypes: ["temperature", "humidity"]
+ },
+ {
+ id: "Oficina 2",
+ //name: "Oficina-",
+ position: { x: 35.85, y: -2.24, z: 16.86 }, // x: 0, y: 25.03, z: -2.52 (23.94, -3.85, 16.86)
+ sensorTypes: ["temperature", "humidity"]
+ },
+ {
+ id: "Oficina 1",
+ //name: "Oficina-",
+ position: { x: 6.98, y: -2.24, z: 16.86 }, // x: 0, y: 25.03, z: -2.52 (-4.93, -3.85, 16.86)
+ sensorTypes: ["temperature", "humidity"]
+ }
+
+ //{
+ // id: "Oficina 5",
+ // //name: "Oficina-",
+ // position: { x: 3.35, y: -4.81, z: 12.88 }, // x: 0, y: 25, z: -2.5 (3.35, -4.81, 12.88
+ // sensorTypes: ["temperature", "humidity"]
+ //},
+ //{
+ // id: "Oficina 4",
+ // //name: "Oficina-",
+ // position: { x: 37.03, y: -4.81, z: 12.88 }, // x: 0, y: 25.03, z: -2.52 (37.03, -4.81, 12.88)
+ // sensorTypes: ["temperature", "humidity"]
+ //},
+ //{
+ // id: "Oficina 3",
+ // //name: "Oficina-",
+ // position: { x: 2.83, y: -22.60, z: 12.88 }, // x: 0, y: 25.03, z: -2.52 (2.83, -22.60, 12.88)
+ // sensorTypes: ["temperature", "humidity"]
+ //}
+ ];
+ //冷氣N5: (6.98, -19.00, 16.86), N4: (35.85, -2.24, 16.86), N3: (6.98, -2.24, 16.86)
+
+ // Initialize sensor values
+ let sensorVals = [];
+ for (let i = 0; i < devices.length; i++) {
+ sensorVals[i] = Math.random();
+ }
+
+ //var offset = Autodesk.viewer.model.getGlobalOffset();
+ //removeOffset(devices[0], offset)
+
+ //---------------- test node ---------------
+
+ // Retrive all dbIds that compose the stadium roof.
+ const it = viewer.model.getInstanceTree();
+ const roomDbIds = [];
+
+ //it.enumNodeChildren(
+ // 5027,//4239
+ // (id) => {
+ // if (it.getNodeName(id) == "【ARC】【樓板】RC") {//【ARC】【樓板】RC 樓板
+ // roomDbIds.push(id);
+ // }
+ // },
+ // true
+ //);
+ roomDbIds.push(11449);//5113 834 838 8106 8177 792 8181 7567
+ //roomDbIds.push(8183);
+ //roomDbIds.push(8185);
+
+ const {
+ SurfaceShadingData,
+ SurfaceShadingPoint,
+ SurfaceShadingNode,
+ } = Autodesk.DataVisualization.Core;
+
+ const shadingNode = new SurfaceShadingNode("Room Panel", roomDbIds);
+
+ devices.forEach((device) => {
+ const shadingPoint = new SurfaceShadingPoint(
+ device.id,
+ device.position,
+ device.sensorTypes
+ );
+ shadingNode.addPoint(shadingPoint);
+ });
+
+ // Generates `SurfaceShadingData` after assigning each device to a room.
+ //const shadingData = await Autodesk.structureInfo.generateSurfaceShadingData(devices);
+ //const shadingData = await structureInfo.generateSurfaceShadingData(devices);
+ //shadingData.initialize(model);
+ const heatmapData = new SurfaceShadingData();
+ heatmapData.addChild(shadingNode);
+ heatmapData.initialize(model);
+
+ // Setup surface shading
+ await dataVizExtn.setupSurfaceShading(model, heatmapData);
+
+ //dataVizExtn.registerSurfaceShadingColors("co2", [0x00ff00, 0xff0000]);
+ dataVizExtn.registerSurfaceShadingColors("temperature", [0xff0000, 0x0000ff]);
+
+ function getSensorValue(device, sensorType) {
+ return sensorVals[parseInt(device.id.slice(-1)) - 1]; // 值: 0~1之間
+ //return 0;
+ }
+
+
+ dataVizExtn.renderSurfaceShading("Room Panel", "temperature", getSensorValue);
+
+ setInterval(() => {
+ // Modify sensor values.
+ for (let i = 0; i < devices.length; i++) {
+ sensorVals[i] = Math.random();
+ }
+ dataVizExtn.updateSurfaceShading(getSensorValue);
+ }, 2000);
+
+ //viewer.hide(5108);//五樓底下的六樓物件
+ //-------------------------------------------------------------------------------
+
+
+ // Use the resulting shading data to generate heatmap from.
+ //await dataVizExtn.setupSurfaceShading(model, shadingData);
+
+ // Register color stops for the heatmap. Along with the normalized sensor value
+ // in the range of [0.0, 1.0], `renderSurfaceShading` will interpolate the final
+ // heatmap color based on these specified colors.
+ //const sensorColors = [0x0000ff, 0x00ff00, 0xffff00, 0xff0000];
+
+ // Set heatmap colors for temperature
+ //const sensorType = "temperature";
+ //dataVizExtn.registerSurfaceShadingColors(sensorType, sensorColors);
+
+ // Function that provides sensor value in the range of [0.0, 1.0]
+
+ //function getSensorValue(surfaceShadingPoint, sensorType) {
+ // // The `SurfaceShadingPoint.id` property matches one of the identifiers passed
+ // // to `generateSurfaceShadingData` function. In our case above, this will either
+ // // be "cafeteria-entrace-01" or "cafeteria-exit-01".
+ // const deviceId = surfaceShadingPoint.id;
+
+ // // Read the sensor data, along with its possible value range
+ // let sensorValue = readSensorValue(deviceId, sensorType);
+ // const maxSensorValue = getMaxSensorValue(sensorType);
+ // const minSensorValue = getMinSensorValue(sensorType);
+
+ // // Normalize sensor value to [0, 1.0]
+ // sensorValue = (sensorValue - minSensorValue) / (maxSensorValue - minSensorValue);
+ // return clamp(sensorValue, 0.0, 1.0);
+ //}
+
+ // This value can also be a room instead of a floor
+ //const floorName = "01 - Entry Level";
+ //dataVizExtn.renderSurfaceShading(floorName, sensorType, getSensorValue);
+
+ //dataVizExtn.updateSurfaceShading(getSensorValue);
+
+}
+
+async function loadHeatmap() {
+ const model = viewer.model;
+ loadHeatmaps(model);
+}
+
+function hideObject() {
+ //viewer.hide(4);
+ //viewer.hide(58);
+ //viewer.hide(613);
+ //viewer.hide(640);
+ //viewer.hide(560);
+
+ for (var i = 0; i < allDbIdsStr.length; i++) {
+ viewer.hide(parseInt(allDbIdsStr[i]));
+ }
+}
+
+function openObject() {
+ //viewer.show(4);
+ //viewer.show(58);
+ //viewer.show(613);
+ //viewer.show(640);
+ //viewer.show(560);
+
+ for (var i = 0; i < allDbIdsStr.length; i++) {
+ viewer.show(parseInt(allDbIdsStr[i]));
+ }
+}
+
+async function setObjectTransparent() {
+ //setTransparency(4, 0);
+ //setTransparency(58, 0);
+ //setTransparency(613, 0);
+ //setTransparency(640, 0);
+ //setTransparency(560, 0);
+ //setTransparency(parseInt(515), 0);
+
+ //for (var i = 0; i < allDbIdsStr.length; i++) {
+ // setTransparency(parseInt(allDbIdsStr[i]), 0);
+ //}
+
+ //setTransparency(parseInt(515), 0);
+ //setTransparency(parseInt(516), 0);
+ //setTransparency(parseInt(517), 0);
+ //setTransparency(parseInt(518), 0);
+ //setTransparency(parseInt(519), 0);
+ //setTransparency(parseInt(399), 0);
+ //setTransparency(parseInt(101), 0);
+ //setTransparency(parseInt(100), 0);
+ //setTransparency(parseInt(58), 0);
+
+ //setTransparency(parseInt(587), 0);
+ //setTransparency(parseInt(586), 0);
+ //setTransparency(parseInt(585), 0);
+ //setTransparency(parseInt(584), 0);
+ //setTransparency(parseInt(583), 0);
+ //setTransparency(parseInt(562), 0);
+ //setTransparency(parseInt(361), 0);
+
+ //test();
+ //hideColor(587);
+ //hideColor(586);
+ //hideColor(585);
+ //hideColor(584);
+ //hideColor(583);
+ //hideColor(562);
+ //hideColor(361);
+
+ setTransparentBuilding();
+
+}
+
+async function cancelObjectTransparent() {
+ //setTransparency(4, 1);
+ //setTransparency(58, 1);
+ //setTransparency(613, 1);
+ //setTransparency(640, 1);
+ //setTransparency(560, 1);
+ //for (var i = 0; i < allDbIdsStr.length; i++) {
+ // setTransparency(parseInt(allDbIdsStr[i]), 1);
+ //}
+
+ //setTransparency(515, 0.2);
+ //setTransparency(516, 0.2);
+ //setTransparency(517, 0.2);
+ //setTransparency(518, 0.2);
+ //setTransparency(519, 0.2);
+ //setTransparency(399, 0.2);
+ //setTransparency(101, 0.2);
+ //setTransparency(100, 0.2);
+ //setTransparency(58, 0.2);
+
+ recoverTransparentBuilding();
+
+}
+
+async function test() {
+ var model = viewer.model;
+ var nodeId = 560;
+
+ var fragList = viewer.model.getFragmentList();
+
+ var fragIds = []
+
+ model.getData().instanceTree.enumNodeFragments(
+ nodeId, (fragId) => {
+ fragIds.push(fragId)
+ });
+
+ fragIds.forEach((fragId) => {
+ //获取材质
+ var material = fragList.getMaterial(fragId);
+
+ if (material) {
+ //设置透明度
+ material.opacity = 0;
+ material.transparent = true;
+ //标记更新
+ material.needsUpdate = true
+ }
+ })
+
+ //更新viewer
+ viewer.impl.invalidate(true, true, true)
+
+}
+
+
+//------------ 剖面 ----------------------
+async function getRemoteLevels() {
+ const aecData = await Autodesk.Viewing.Document.getAecModelData(this.viewer.model.getDocumentNode());
+ if (!aecData.levels) return null;
+
+ const levels = aecData.levels;
+ levels.sort((a, b) => b.elevation - a.elevation);
+ return levels;
+}
+
+async function getLevelsData() {
+ const data = await this.getRemoteLevels();
+ this.levels = data;
+}
+
+//function getCutPlaneParam(idx, n) {
+// if (idx < 0 || !n) return;
+
+// const level = this.levels[idx];
+// if (!level) return;
+
+// //const precision = Autodesk.Viewing.Private.calculatePrecision( level.elevation );
+// const model = this.viewer.model;
+// const globalOffset = model.getData().globalOffset;
+// const units = model.getUnitString();
+// const elevRaw = Autodesk.Viewing.Private.convertUnits('ft', units, 1, level.elevation);
+
+// let d = elevRaw - globalOffset.z - 0.5;
+// if (n == 1)
+// d = -1 * d;
+
+// return new THREE.Vector4(0, 0, n, d);
+//}
+
+
+function profile() {
+ const upperIdx = 6;
+ const upperCutPlaneParam = this.getCutPlaneParam(upperIdx, 1);
+ const lowerIdx = 7;
+ const lowerCutPlaneParam = this.getCutPlaneParam(lowerIdx, -1);
+ this.viewer.setCutPlanes([upperCutPlaneParam, lowerCutPlaneParam]);
+}
+//----------------- end -----------------------------------------------
+
+// 設備的dbid和3D座標 存進 資料庫
+//function ImportDevForCor() {//callback = null
+// var url = "/DeviceImport/ImportDevForCor";
+// //let sendData = {
+// // "device_number": pageAct.AreaTag,
+// // "device_coordinate_3d": "",
+// // "device_dbid": "",
+// //};
+// objSendData.Data = tagIdDevList;
+// //ytAjax = new YourTeam.Ajax(url, objSendData, function (res) {
+// // if (!res || res.code != "0000" || !res.data) {
+
+// // } else {
+
+// // }
+// //}, null, "POST").send();
+
+// //$.post(url, objSendData, function (rel) {
+// // if (rel.code != "0000") {
+// // if (rel.code == "9999") {
+// // toast_error(rel.msg);
+// // }
+// // else {
+// // toast_warning(rel.msg);
+// // }
+// // return;
+// // }
+// // else {
+// // toast_ok(rel.msg);
+// // //ReloadRawDataCheckTable();
+// // }
+
+// //}, 'json');
+
+// //headers={'content-type': 'application/json'}
+
+// $.ajax({
+// type: "POST",
+// url: url,
+// data: objSendData,
+// cache: false,
+// contentType: 'application/json',
+// processData: false,
+// success: function (rel) {
+// //$("#save-building-btn").html('確定').attr("disabled", false);
+// if (rel.code != "0000") {
+// if (rel.code == "9999") {
+// toast_error(rel.msg);
+// }
+// else {
+// toast_warning(rel.msg);
+// }
+// return;
+// }
+// else {
+// toast_ok(rel.msg);
+// //buildInfoTable.ajax.reload(null, false);
+// //$('#build-modal').modal('hide');
+// return;
+// }
+// },
+// fail: function (xhr, status, error) {
+// //$("#save-building-btn").html('確定').attr("disabled", false);
+// //toast_error(rel.msg);
+// }
+// });
+
+//}
\ No newline at end of file
diff --git a/Backend/wwwroot/js/forge/ForgeTree.js b/Backend/wwwroot/js/forge/ForgeTree.js
new file mode 100644
index 0000000..885d463
--- /dev/null
+++ b/Backend/wwwroot/js/forge/ForgeTree.js
@@ -0,0 +1,166 @@
+
+$(document).ready(function () {
+ prepareAppBucketTree();
+ $('#refreshBuckets').click(function () {
+ $('#appBuckets').jstree(true).refresh();
+ });
+
+ $('#createNewBucket').click(function () {
+ createNewBucket();
+ });
+
+ $('#createBucketModal').on('shown.bs.modal', function () {
+ $("#newBucketKey").focus();
+ })
+
+ $('#hiddenUploadField').change(function () {
+ var node = $('#appBuckets').jstree(true).get_selected(true)[0];
+ var _this = this;
+ if (_this.files.length == 0) return;
+ var file = _this.files[0];
+ switch (node.type) {
+ case 'bucket':
+ var formData = new FormData();
+ formData.append('fileToUpload', file);
+ formData.append('bucketKey', node.id);
+
+ $.ajax({
+ url: '/api/forge/oss/objects',
+ data: formData,
+ processData: false,
+ contentType: false,
+ type: 'POST',
+ success: function (data) {
+ $('#appBuckets').jstree(true).refresh_node(node);
+ _this.value = '';
+ }
+ });
+ break;
+ }
+ });
+});
+
+function createNewBucket() {
+ var bucketKey = $('#newBucketKey').val();
+ var policyKey = $('#newBucketPolicyKey').val();
+ jQuery.post({
+ url: '/api/forge/oss/buckets',
+ contentType: 'application/json',
+ data: JSON.stringify({ 'bucketKey': bucketKey, 'policyKey': policyKey }),
+ success: function (res) {
+ $('#appBuckets').jstree(true).refresh();
+ $('#createBucketModal').modal('toggle');
+ },
+ error: function (err) {
+ if (err.status == 409)
+ alert('Bucket already exists - 409: Duplicated')
+ console.log(err);
+ }
+ });
+}
+
+function prepareAppBucketTree() {
+ $('#appBuckets').jstree({
+ 'core': {
+ 'themes': { "icons": true },
+ 'data': {
+ "url": '/api/forge/oss/buckets',
+ "dataType": "json",
+ 'multiple': false,
+ "data": function (node) {
+ return { "id": node.id };
+ }
+ }
+ },
+ 'types': {
+ 'default': {
+ 'icon': 'glyphicon glyphicon-question-sign'
+ },
+ '#': {
+ 'icon': 'glyphicon glyphicon-cloud'
+ },
+ 'bucket': {
+ 'icon': 'glyphicon glyphicon-folder-open'
+ },
+ 'object': {
+ 'icon': 'glyphicon glyphicon-file'
+ }
+ },
+ "plugins": ["types", "state", "sort", "contextmenu"],
+ contextmenu: { items: autodeskCustomMenu }
+ }).on('loaded.jstree', function () {
+ $('#appBuckets').jstree('open_all');
+ }).bind("activate_node.jstree", function (evt, data) {
+ if (data != null && data.node != null && data.node.type == 'object') {
+ $("#forgeViewer").empty();
+ var urn = data.node.id;
+ getForgeToken(function (access_token) {
+ jQuery.ajax({
+ url: 'https://developer.api.autodesk.com/modelderivative/v2/designdata/' + urn + '/manifest',
+ headers: { 'Authorization': 'Bearer ' + access_token },
+ success: function (res) {
+ if (res.progress === 'success' || res.progress === 'complete') launchViewer(urn);
+ else $("#forgeViewer").html('The translation job still running: ' + res.progress + '. Please try again in a moment.');
+ },
+ error: function (err) {
+ var msgButton = 'This file is not translated yet! ' +
+ '
' +
+ 'Start translation'
+ $("#forgeViewer").html(msgButton);
+ }
+ });
+ })
+ }
+ });
+}
+
+function autodeskCustomMenu(autodeskNode) {
+ var items;
+
+ switch (autodeskNode.type) {
+ case "bucket":
+ items = {
+ uploadFile: {
+ label: "Upload file",
+ action: function () {
+ uploadFile();
+ },
+ icon: 'glyphicon glyphicon-cloud-upload'
+ }
+ };
+ break;
+ case "object":
+ items = {
+ translateFile: {
+ label: "Translate",
+ action: function () {
+ var treeNode = $('#appBuckets').jstree(true).get_selected(true)[0];
+ translateObject(treeNode);
+ },
+ icon: 'glyphicon glyphicon-eye-open'
+ }
+ };
+ break;
+ }
+
+ return items;
+}
+
+function uploadFile() {
+ $('#hiddenUploadField').click();
+}
+
+function translateObject(node) {
+ $("#forgeViewer").empty();
+ if (node == null) node = $('#appBuckets').jstree(true).get_selected(true)[0];
+ var bucketKey = node.parents[0];
+ var objectKey = node.id;
+ jQuery.post({
+ url: '/api/forge/modelderivative/jobs',
+ contentType: 'application/json',
+ data: JSON.stringify({ 'bucketKey': bucketKey, 'objectName': objectKey }),
+ success: function (res) {
+ $("#forgeViewer").html('Translation started! Please try again in a moment.');
+ },
+ });
+}
\ No newline at end of file
diff --git a/Backend/wwwroot/js/forge/ForgeViewer.js b/Backend/wwwroot/js/forge/ForgeViewer.js
new file mode 100644
index 0000000..0f68f93
--- /dev/null
+++ b/Backend/wwwroot/js/forge/ForgeViewer.js
@@ -0,0 +1,35 @@
+
+var viewer;
+
+function launchViewer(urn) {
+ var options = {
+ env: 'AutodeskProduction',
+ getAccessToken: getForgeToken
+ };
+
+ Autodesk.Viewing.Initializer(options, () => {
+ viewer = new Autodesk.Viewing.GuiViewer3D(document.getElementById('forgeViewer'));
+ viewer.start();
+ var documentId = 'urn:' + urn;
+ Autodesk.Viewing.Document.load(documentId, onDocumentLoadSuccess, onDocumentLoadFailure);
+ });
+}
+
+function onDocumentLoadSuccess(doc) {
+ var viewables = doc.getRoot().getDefaultGeometry();
+ viewer.loadDocumentNode(doc, viewables).then(i => {
+ // documented loaded, any action?
+ });
+}
+
+function onDocumentLoadFailure(viewerErrorCode) {
+ console.error('onDocumentLoadFailure() - errorCode:' + viewerErrorCode);
+}
+
+function getForgeToken(callback) {
+ fetch('/api/forge/oauth/token').then(res => {
+ res.json().then(data => {
+ callback(data.access_token, data.expires_in);
+ });
+ });
+}
\ No newline at end of file