diff --git a/Frontend/forgeTest.html b/Frontend/forgeTest.html
new file mode 100644
index 0000000..5f78e4d
--- /dev/null
+++ b/Frontend/forgeTest.html
@@ -0,0 +1,53 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Frontend/forgetAnim1.html b/Frontend/forgetAnim1.html
new file mode 100644
index 0000000..883d698
--- /dev/null
+++ b/Frontend/forgetAnim1.html
@@ -0,0 +1,228 @@
+/////////////////////////////////////////////////////////////////////
+// Explorer viewer extension
+// by Philippe Leefsma, March 2015
+//
+/////////////////////////////////////////////////////////////////////
+AutodeskNamespace("Autodesk.ADN.Viewing.Extension");
+
+
+Autodesk.ADN.Viewing.Extension.Explorer = function (viewer, options) {
+
+ Autodesk.Viewing.Extension.call(this, viewer, options);
+
+ var _self = this;
+
+ var _viewer = viewer;
+
+ /////////////////////////////////////////////////////////////////
+ // The Explorer tool
+ //
+ /////////////////////////////////////////////////////////////////
+ function ExplorerTool(viewer) {
+
+ this.getNames = function() {
+
+ return ["Autodesk.ADN.Viewing.Tool.ExplorerTool"];
+ };
+
+ this.getName = function() {
+
+ return "Autodesk.ADN.Viewing.Tool.ExplorerTool";
+ };
+
+ /////////////////////////////////////////////////////////////
+ // called when tool is activated
+ //
+ /////////////////////////////////////////////////////////////
+ this.activate = function(name) {
+
+ _viewer.navigation.setRequestHomeView(true);
+
+ var position = _viewer.navigation.getPosition();
+ var target = _viewer.navigation.getTarget();
+ var worldUp = _viewer.navigation.getWorldUpVector();
+
+ var pt = {
+ x: position.x - target.x,
+ y: position.y - target.y,
+ z: position.z - target.z
+ }
+
+ this.height = dotProduct(pt, worldUp);
+
+ var rVect = getPerpendicularVector(worldUp);
+
+ this.radius = dotProduct(pt, rVect);
+ };
+
+ /////////////////////////////////////////////////////////////
+ // called when tool is deactivated
+ //
+ /////////////////////////////////////////////////////////////
+ this.deactivate = function(name) {
+
+ this.activated = false;
+ };
+
+ this.speed = 0.3;
+ this.phase = "1";
+ this.switchPhase = true;
+
+ /////////////////////////////////////////////////////////////
+ // update is called by the framework
+ // t: time elapsed since tool activated in ms
+ /////////////////////////////////////////////////////////////
+ this.update = function(t) {
+
+ var target = _viewer.navigation.getTarget();
+ var worldUp = _viewer.navigation.getWorldUpVector();
+
+ var offset = Math.abs(Math.cos(this.speed * t * 0.001));
+
+ // create some effect to keep camera near object
+ // while it orbits for a while
+ if(offset < 0.01) {
+
+ if(this.switchPhase) {
+
+ this.switchPhase = false;
+
+ if (this.phase === "1") {
+ this.phase = "2";
+ }
+ else if (this.phase === "2") {
+ this.phase = "1";
+ }
+ }
+ }
+
+ if(offset > 0.99) {
+ this.switchPhase = true;
+ }
+
+ if(this.phase === "1")
+ this.offset = offset;
+
+ var height = this.height * (0.5 + 1.5 * this.offset);
+
+ var radius = this.radius * (0.5 + 1.5 * this.offset);
+
+ var center = {
+ x: target.x + height * worldUp.x,
+ y: target.y + height * worldUp.y,
+ z: target.z + height * worldUp.z
+ }
+
+ var pos = computeCirclularTrajectory(
+ this.speed * t * 0.001,
+ radius,
+ worldUp,
+ center);
+
+ _viewer.navigation.setPosition(pos);
+
+ return false;
+ };
+
+ /////////////////////////////////////////////////////////////
+ // utilities
+ //
+ /////////////////////////////////////////////////////////////
+ function crossProduct(u, v) {
+
+ return {
+
+ x: u.y * v.z - u.z * v.y,
+ y: u.z * v.x - u.x * v.z,
+ z: u.x * v.y - u.y * v.x
+ }
+ }
+
+ function dotProduct(u, v) {
+
+ return Math.abs(
+ u.x * v.x +
+ u.y * v.y +
+ u.z * v.z);
+ }
+
+ function norm(v) {
+
+ return Math.sqrt(
+ v.x * v.x +
+ v.y * v.y +
+ v.z * v.z);
+ }
+
+ function getPerpendicularVector(v) {
+
+ var u = { x: 0, y: 0, z: 0 };
+
+ if(v.x !== 0)
+ u = { x: 0, y: 1, z: 0 };
+ else if(v.y !== 0)
+ u = { x: 1, y: 0, z: 0 };
+ else
+ u = { x: 1, y: 0, z: 0 };
+
+ return crossProduct(v, u);
+ }
+
+ function computeCirclularTrajectory(t, radius, normal, center) {
+
+ // C: center, n: normal, u: perpendicular to n
+ // p(t) = r.cos(t).u + r.sin(t).(n x u) + C
+
+ var u = getPerpendicularVector(normal);
+
+ var v = crossProduct(u, normal);
+
+ var pos = {
+
+ x: radius * Math.cos(t) * u.x + radius * Math.sin(t) * v.x + center.x,
+ y: radius * Math.cos(t) * u.y + radius * Math.sin(t) * v.y + center.y,
+ z: radius * Math.cos(t) * u.z + radius * Math.sin(t) * v.z + center.z
+ };
+
+ return pos;
+ }
+ }
+
+ /////////////////////////////////////////////////////////////////
+ // load callback
+ //
+ /////////////////////////////////////////////////////////////////
+ _self.load = function () {
+
+ _self.tool = new ExplorerTool(_viewer);
+
+ _viewer.toolController.registerTool(_self.tool);
+
+ _viewer.toolController.activateTool(_self.tool.getName());
+
+ console.log('Autodesk.ADN.Viewing.Extension.Explorer loaded');
+ return true;
+ };
+
+ /////////////////////////////////////////////////////////////////
+ // unload callback
+ //
+ /////////////////////////////////////////////////////////////////
+ _self.unload = function () {
+
+ _viewer.toolController.deactivateTool(_self.tool.getName());
+
+ console.log('Autodesk.ADN.Viewing.Extension.Explorer unloaded');
+ return true;
+ };
+};
+
+Autodesk.ADN.Viewing.Extension.Explorer.prototype =
+ Object.create(Autodesk.Viewing.Extension.prototype);
+
+Autodesk.ADN.Viewing.Extension.Explorer.prototype.constructor =
+ Autodesk.ADN.Viewing.Extension.Explorer;
+
+Autodesk.Viewing.theExtensionManager.registerExtension(
+ 'Autodesk.ADN.Viewing.Extension.Explorer',
+ Autodesk.ADN.Viewing.Extension.Explorer);
\ No newline at end of file
diff --git a/Frontend/forgetTest2.html b/Frontend/forgetTest2.html
new file mode 100644
index 0000000..31b822e
--- /dev/null
+++ b/Frontend/forgetTest2.html
@@ -0,0 +1,241 @@
+
+
+
+
+
+
+
+
+
+
+
+ Showing A360 Shared files
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Frontend/js/forge/forgemodel.js b/Frontend/js/forge/forgemodel.js
new file mode 100644
index 0000000..5f538e8
--- /dev/null
+++ b/Frontend/js/forge/forgemodel.js
@@ -0,0 +1,170 @@
+var viewer;
+
+const devices = [
+ {
+ id: "Sensor 1",
+ position: {
+ x: -22.779729106182415,
+ y: 5.431043023608719,
+ z: 4.553068469137088,
+ },
+ type: "combo",
+ sensorTypes: ["temperature", "co2"],
+ dbId: 1,
+ },
+ {
+ id: "Sensor 2",
+ position: {
+ x: 0.20752051811882666,
+ y: 5.431043023608719,
+ z: 4.553068469137088,
+ },
+ type: "combo",
+ sensorTypes: ["temperature", "co2"],
+ dbId: 2,
+ },
+];
+
+var sensorStyleDefinitions = {
+ co2: {
+ url: "https://d2zqnmauvnpnnm.cloudfront.net/assets-1/images/co2.svg",
+ color: 0xffffff,
+ },
+ temperature: {
+ url: "https://d2zqnmauvnpnnm.cloudfront.net/assets-1/images/thermometer.svg",
+ color: 0xffffff,
+ },
+ default: {
+ url: "https://d2zqnmauvnpnnm.cloudfront.net/assets-1/images/circle.svg",
+ color: 0xffffff,
+ },
+};
+
+// Initialize sensor values
+let sensorVals = [];
+for (let i = 0; i < devices.length; i++) {
+ sensorVals[i] = Math.random();
+}
+
+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);
+
+
+
+ //test
+ for (let i = 0; i < urns.length; i++) {
+ Autodesk.Viewing.Document.load(urns[i]["urn"], async (doc) => {
+ let viewables = doc.getRoot().getDefaultGeometry();
+ let model = await viewer.loadDocumentNode(doc, viewables, {
+ preserveView: false,
+ keepCurrentModels: true,
+ placementTransform: (new THREE.Matrix4()).setPosition(urns[i]["xform"]),
+ keepCurrentModels: true,
+ globalOffset: {
+ x: 0,
+ y: 0,
+ z: 0
+ }
+ });
+
+ await viewer.waitForLoadDone(); //!<<< Wait for loading materials, properties and geometries for this model (URN)
+ });
+ }
+
+ loadHeatmaps(viewer.getAllModels()[0]); //!<<< equals to viewer.model
+
+
+
+ });
+}
+
+function onDocumentLoadSuccess(doc) {
+ var viewables = doc.getRoot().getDefaultGeometry();
+ viewer.loadDocumentNode(doc, viewables).then(i => {
+ // documented loaded, any action?
+ });
+
+}
+
+/**
+ * Autodesk.Viewing.Document.load() failuire callback.
+ */
+function onDocumentLoadFailure(viewerErrorCode) {
+ console.error("onDocumentLoadFailure() - errorCode:" + viewerErrorCode);
+}
+
+function getForgeToken(callback) {
+ fetch('http://localhost:3604/api/forge/oauth/token').then(res => {
+ res.json().then(data => {
+ callback(data.dictionary.access_token, data.dictionary.expires_in);
+ });
+ });
+ //callback("eyJhbGciOiJSUzI1NiIsImtpZCI6IlU3c0dGRldUTzlBekNhSzBqZURRM2dQZXBURVdWN2VhIn0.eyJzY29wZSI6WyJkYXRhOndyaXRlIiwiZGF0YTpyZWFkIiwiYnVja2V0OnJlYWQiLCJidWNrZXQ6dXBkYXRlIiwiYnVja2V0OmNyZWF0ZSJdLCJjbGllbnRfaWQiOiJUQTNocXNGZnpRYk5PVVhLcGxkS1VLU2V3NFNKMjF3NSIsImF1ZCI6Imh0dHBzOi8vYXV0b2Rlc2suY29tL2F1ZC9hand0ZXhwNjAiLCJqdGkiOiJiemxzWE5qWElvZ2R1UjUzTUJkdlhrTTNTT01qeVB1bHJrMmdTVWJudGNTeDg1b01kRG1xejg3Z05jenJkRzhpIiwiZXhwIjoxNjY4MTgzMDM2fQ.VU3qLwTJ9nlXnomKCdk4y5UcgszGEO_zlvE7w5mWWajeBMwKLo-zw7LJEqUEajRksvssppR9SbVsjLSx-vDVc3DRhCo3jYTWKPT1T3wQrlkOSqLeIrAdnKdBDNBWKgrGJt_xcmXc3dZ3XNKf9L_F6Ex808rUlo6cem1mcPpKl1jCBDqKu1mAX7aDtZ65TTQZbGGhbG4HdnET-d1i5w4LunGN11UAHhDUW3n0SWWIBL27PiiUQONZttajhD5st6IngYLcjr93BYVyJmDF7-wm4WZlHSw2OnXIfbJcFXEd83uVv_Rej4UXjzZ0e6kHwzc2nvGvKSIFu3Nt7CabdR8CkA", 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);
+
+ const devices = [
+ {
+ id: "Oficina 6",
+ name: "Oficina-",
+ position: { x: 22.475382737884104, y: 7.4884431474006163, z: 3.0 },
+ sensorTypes: ["temperature", "humidity"]
+ }
+ ];
+
+ var offset = Autodesk.viewer.model.getGlobalOffset();
+ removeOffset(devices[0], offset)
+
+ // Generates `SurfaceShadingData` after assigning each device to a room.
+
+ const shadingData = await Autodesk.structureInfo.generateSurfaceShadingData(devices);
+
+ // 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);
+}