Zwt 1 неделя назад
Родитель
Сommit
36973e6277
5 измененных файлов с 616 добавлено и 25 удалено
  1. 9 1
      edit.html
  2. 340 5
      js/edit.js
  3. 41 10
      js/main_2020_edit.js
  4. 34 9
      js/main_2020_show.js
  5. 192 0
      js/manage.js

+ 9 - 1
edit.html

@@ -107,6 +107,10 @@
                         <span class="panoVisible"></span>
                         <span class="panoVisible"></span>
                         <label>漫游点位</label>
                         <label>漫游点位</label>
                     </li>
                     </li>
+                    <li data-name="groundAdjust">
+                        <span class="panoVisible"></span>
+                        <label>地面点调整</label>
+                    </li>
                     <li data-name="routeArrow">
                     <li data-name="routeArrow">
                         <span class="panoVisible"></span>
                         <span class="panoVisible"></span>
                         <label>路线指引</label>
                         <label>路线指引</label>
@@ -1912,6 +1916,10 @@
                 
                 
                 
                 
                 
                 
+                <div class="groundAdjust content hide" style="font-family:'Microsoft YaHei','PingFang SC','Hiragino Sans GB',sans-serif;">
+                    <ul class="view-setting">
+                    </ul>
+                </div>
                 <div class="routeArrow content hide">
                 <div class="routeArrow content hide">
                     <ul >
                     <ul >
                         <li>
                         <li>
@@ -2080,4 +2088,4 @@
     <script src="js/loadCAD.js"></script>
     <script src="js/loadCAD.js"></script>
 </body>
 </body>
 
 
-</html>
+</html>

Разница между файлами не показана из-за своего большого размера
+ 340 - 5
js/edit.js


+ 41 - 10
js/main_2020_edit.js

@@ -14105,6 +14105,8 @@ function o(a, s, l) {
                 
                 
                 t.hotIconScale = parseFloat(t.hotIconScale || 1) 
                 t.hotIconScale = parseFloat(t.hotIconScale || 1) 
                 window.DATA = t
                 window.DATA = t
+                window.DATA.puckHeight || window.DATA.info && window.DATA.info.puckHeight && (window.DATA.puckHeight = window.DATA.info.puckHeight)
+                window.PuckHeightHelper && (window.DATA.puckHeight = window.PuckHeightHelper.normalizeConfig(window.DATA.puckHeight))
                 settings.playTourNearBy = !DATA.tourFromStart
                 settings.playTourNearBy = !DATA.tourFromStart
                 
                 
                 t.model.summary = t.summary
                 t.model.summary = t.summary
@@ -17218,6 +17220,8 @@ function o(a, s, l) {
                 this.panos.forEach(function(e) {
                 this.panos.forEach(function(e) {
                     e.build2()
                     e.build2()
                 }),
                 }),
+                window.PuckHeightHelper && (window.PuckHeightHelper.captureBaseFloorPosition(this),
+                window.PuckHeightHelper.applyToModel(this, window.DATA && window.DATA.puckHeight)),
                 this.floors.forEach(function(e) {
                 this.floors.forEach(function(e) {
                     this.boundingBox.union(e.boundingBox)
                     this.boundingBox.union(e.boundingBox)
                 }
                 }
@@ -17365,7 +17369,9 @@ function o(a, s, l) {
                         var shows = [],  hides = []  
                         var shows = [],  hides = []  
 
 
                         player.model.panos.forEach(pano => { //是邻近点就显示否则隐藏 
                         player.model.panos.forEach(pano => { //是邻近点就显示否则隐藏 
-                            if (currentPano.neighbourPanos[pano.id]) { 
+                            if (pano.id === currentPano.id) {
+                                hides.push(pano)
+                            } else if (currentPano.neighbourPanos[pano.id]) { 
                                 shows.push(pano) 
                                 shows.push(pano) 
                             } else {
                             } else {
                                 hides.push(pano)
                                 hides.push(pano)
@@ -18166,8 +18172,9 @@ function o(a, s, l) {
             ,
             ,
             r.prototype.raycastFloorPosition = function() {
             r.prototype.raycastFloorPosition = function() {
                 I.warn("Performance warning: Raycasting to find floor position");
                 I.warn("Performance warning: Raycasting to find floor position");
-                var e = new s.Raycaster(this.position,new s.Vector3(0,-1,0)).intersectObjects(this.model.colliders);
-                return e.length ? e[0].point : null
+                var e = this.floor && this.floor.collider && this.floor.collider.children && this.floor.collider.children.length ? this.floor.collider.children : this.model.colliders
+                  , t = new s.Raycaster(this.position,new s.Vector3(0,-1,0)).intersectObjects(e, !0);
+                return t.length ? t[0].point : null
             }
             }
             ,
             ,
             r.prototype.raycastToFindFloor = (i = [new s.Vector3(0,-1,0), new s.Vector3(1,-1,0), new s.Vector3(0,-1,1), new s.Vector3(-1,-1,0), new s.Vector3(0,-1,-1), new s.Vector3(1,0,0), new s.Vector3(0,0,1), new s.Vector3(-1,0,0), new s.Vector3(0,0,-1)],
             r.prototype.raycastToFindFloor = (i = [new s.Vector3(0,-1,0), new s.Vector3(1,-1,0), new s.Vector3(0,-1,1), new s.Vector3(-1,-1,0), new s.Vector3(0,-1,-1), new s.Vector3(1,0,0), new s.Vector3(0,0,1), new s.Vector3(-1,0,0), new s.Vector3(0,0,-1)],
@@ -18189,7 +18196,8 @@ function o(a, s, l) {
             ,
             ,
             r.prototype.translate = function(e) {
             r.prototype.translate = function(e) {
                 this.position.add(e),
                 this.position.add(e),
-                this.floorPosition.add(e)
+                this.floorPosition.add(e),
+                this.baseFloorPosition && this.baseFloorPosition.add(e)
             }
             }
             ,
             ,
             r.prototype.findClosestMidtpointPanoTo = function(e) {
             r.prototype.findClosestMidtpointPanoTo = function(e) {
@@ -18954,6 +18962,18 @@ function o(a, s, l) {
                 this.currentPanoMarker.mesh.parent || e.add(this.currentPanoMarker.mesh)
                 this.currentPanoMarker.mesh.parent || e.add(this.currentPanoMarker.mesh)
             }
             }
             ,
             ,
+            t.prototype.shouldHideCpmAtCurrentPano = function() {
+                return this.player && this.player.mode === O.PANORAMA && this.player.currentPano && this.player.currentPano.isAligned()
+            }
+            ,
+            t.prototype.syncCpmVisibility = function() {
+                if (!this.currentPanoMarker || !this.currentPanoMarker.mesh)
+                    return;
+                var e = this.shouldHideCpmAtCurrentPano();
+                this.currentPanoMarker.mesh.visible = !e,
+                e && this.currentPanoMarker.mesh.material && this.currentPanoMarker.mesh.material.uniforms && this.currentPanoMarker.mesh.material.uniforms.opacity && (this.currentPanoMarker.mesh.material.uniforms.opacity.value = 0)
+            }
+            ,
             t.prototype.placeCpm = function() {
             t.prototype.placeCpm = function() {
                 if (D.path.mapGuides && this.player.currentPano && this.player.currentPano.isAligned()) {
                 if (D.path.mapGuides && this.player.currentPano && this.player.currentPano.isAligned()) {
                     var e = this.player.currentPano.floor;
                     var e = this.player.currentPano.floor;
@@ -18961,17 +18981,22 @@ function o(a, s, l) {
                     e.add(this.currentPanoMarker.mesh)),
                     e.add(this.currentPanoMarker.mesh)),
                     this.currentPanoMarker.mesh.position.copy(this.player.currentPano.floorPosition).sub(e.position),
                     this.currentPanoMarker.mesh.position.copy(this.player.currentPano.floorPosition).sub(e.position),
                     this.currentPanoMarker.mesh.position.y += this.pathHeight(),
                     this.currentPanoMarker.mesh.position.y += this.pathHeight(),
-                    this.currentPanoMarker.placed = !0
+                    this.currentPanoMarker.placed = !0,
+                    this.syncCpmVisibility()
                 } else
                 } else
                     this.popOutCpm()
                     this.popOutCpm()
             }
             }
             ,
             ,
             t.prototype.fadeInCpm = function(e) {
             t.prototype.fadeInCpm = function(e) {
-                this.player.mode === O.PANORAMA && this.player.currentPano && !this.player.currentPano.isAligned() || D.path.mapGuides && this.currentPanoMarker.placed && V.start(F.property(this.currentPanoMarker.mesh.material.uniforms.opacity, "value", 1), e)
+                if (this.shouldHideCpmAtCurrentPano())
+                    return void this.syncCpmVisibility();
+                D.path.mapGuides && this.currentPanoMarker.placed && (this.currentPanoMarker.mesh.visible = !0,
+                V.start(F.property(this.currentPanoMarker.mesh.material.uniforms.opacity, "value", 1), e))
             }
             }
             ,
             ,
             t.prototype.fadeOutCpm = function(e) {
             t.prototype.fadeOutCpm = function(e) {
-                V.start(F.property(this.currentPanoMarker.mesh.material.uniforms.opacity, "value", 0), e)
+                this.currentPanoMarker && this.currentPanoMarker.mesh && this.currentPanoMarker.mesh.material && this.currentPanoMarker.mesh.material.uniforms && this.currentPanoMarker.mesh.material.uniforms.opacity && (this.currentPanoMarker.mesh.material.uniforms.opacity.value = 0),
+                this.syncCpmVisibility()
             }
             }
             ,
             ,
             t.prototype.popInCpm = function() {
             t.prototype.popInCpm = function() {
@@ -21105,6 +21130,10 @@ function o(a, s, l) {
                         this.intersect && this.intersect.object.visible && VisiSet.dealPanoLogClick( this.intersect.object);
                         this.intersect && this.intersect.object.visible && VisiSet.dealPanoLogClick( this.intersect.object);
                         return;
                         return;
                     }
                     }
+                    if (window.VisiSet && VisiSet.setGroundAdjust ) {
+                        this.intersect && this.intersect.object.visible && VisiSet.dealGroundAdjustClick(this.intersect.object);
+                        return;
+                    }
                     if (window.VisiSet && VisiSet.setRoute) {
                     if (window.VisiSet && VisiSet.setRoute) {
                         this.intersect && this.intersect.object.visible && VisiSet.dealRouteClick(this.intersect.object);
                         this.intersect && this.intersect.object.visible && VisiSet.dealRouteClick(this.intersect.object);
                         return;
                         return;
@@ -21649,7 +21678,7 @@ function o(a, s, l) {
                     } 
                     } 
                 }
                 }
                 
                 
-                if (window.VisiSet && (VisiSet.setPanoVisible || VisiSet.setTagVisible || VisiSet.setPanoLog || VisiSet.setPanoArea && VisiSet.editPanoArea || VisiSet.setRoute )) {
+                if (window.VisiSet && (VisiSet.setPanoVisible || VisiSet.setTagVisible || VisiSet.setPanoLog || VisiSet.setGroundAdjust || VisiSet.setPanoArea && VisiSet.editPanoArea || VisiSet.setRoute )) {
                     let meshes = this.model.hotGroup.children.slice()
                     let meshes = this.model.hotGroup.children.slice()
                     if(VisiSet.routeInfo?.operation == 'removeLink'){
                     if(VisiSet.routeInfo?.operation == 'removeLink'){
                         meshes.push(...VisiSet.meshGroup.children.filter(e=>e.name.includes('routeLine:')))
                         meshes.push(...VisiSet.meshGroup.children.filter(e=>e.name.includes('routeLine:')))
@@ -21919,7 +21948,10 @@ function o(a, s, l) {
                 if(this.mode != "panorama")return;
                 if(this.mode != "panorama")return;
                 this.model.panos.list.forEach((pano)=>{
                 this.model.panos.list.forEach((pano)=>{
                     if(!pano.marker)return;
                     if(!pano.marker)return;
-                    pano.marker.material.visible = !!pano.neighbourPanos[this.currentPano.id];
+                    var isCurrent = pano.id == this.currentPano.id;
+                    var isNeighbour = !!pano.neighbourPanos[this.currentPano.id];
+                    pano.marker.material.visible = !isCurrent && isNeighbour;
+                    pano.marker.material.opacity = !isCurrent && isNeighbour ? _settings.panorama.markerOpacity : 0;
                 })
                 })
             }
             }
             ,
             ,
@@ -55946,4 +55978,3 @@ function o(a, s, l) {
 
 
 
 
 
 
-

+ 34 - 9
js/main_2020_show.js

@@ -14742,6 +14742,8 @@ window.Modernizr = function(n, e, t) {
                 
                 
                      
                      
 				window.DATA = data; 
 				window.DATA = data; 
+                window.DATA.puckHeight || window.DATA.info && window.DATA.info.puckHeight && (window.DATA.puckHeight = window.DATA.info.puckHeight);
+                window.PuckHeightHelper && (window.DATA.puckHeight = window.PuckHeightHelper.normalizeConfig(window.DATA.puckHeight));
                 data.model.summary = data.summary
                 data.model.summary = data.summary
                 data.model.name = data.name
                 data.model.name = data.name
                 for(let i in data){
                 for(let i in data){
@@ -18222,6 +18224,8 @@ window.Modernizr = function(n, e, t) {
                 this.panos.forEach(function(e) {
                 this.panos.forEach(function(e) {
                     e.build2()
                     e.build2()
                 }),
                 }),
+                window.PuckHeightHelper && (window.PuckHeightHelper.captureBaseFloorPosition(this),
+                window.PuckHeightHelper.applyToModel(this, window.DATA && window.DATA.puckHeight)),
                 this.floors.forEach(function(e) {
                 this.floors.forEach(function(e) {
                     this.boundingBox.union(e.boundingBox)
                     this.boundingBox.union(e.boundingBox)
                 }
                 }
@@ -18513,7 +18517,9 @@ window.Modernizr = function(n, e, t) {
                         var shows = [],  hides = []  
                         var shows = [],  hides = []  
 
 
                         player.model.panos.forEach(pano => { //是邻近点就显示否则隐藏 
                         player.model.panos.forEach(pano => { //是邻近点就显示否则隐藏 
-                            if (currentPano.neighbourPanos[pano.id]) { 
+                            if (pano.id === currentPano.id) {
+                                hides.push(pano)
+                            } else if (currentPano.neighbourPanos[pano.id]) { 
                                 shows.push(pano) 
                                 shows.push(pano) 
                             } else {
                             } else {
                                 hides.push(pano)
                                 hides.push(pano)
@@ -19661,7 +19667,7 @@ window.Modernizr = function(n, e, t) {
             n.prototype.raycastFloorPosition = function() {
             n.prototype.raycastFloorPosition = function() {
                 I.warn("Performance warning: Raycasting to find floor position");
                 I.warn("Performance warning: Raycasting to find floor position");
                 var e = new r.Raycaster(this.position,new r.Vector3(0,-1,0))
                 var e = new r.Raycaster(this.position,new r.Vector3(0,-1,0))
-                  , t = e.intersectObjects(this.model.colliders);
+                  , t = e.intersectObjects(this.floor && this.floor.collider && this.floor.collider.children && this.floor.collider.children.length ? this.floor.collider.children : this.model.colliders, !0);
                 return t.length ? t[0].point : null
                 return t.length ? t[0].point : null
             }
             }
             ,
             ,
@@ -19691,7 +19697,8 @@ window.Modernizr = function(n, e, t) {
             ,
             ,
             n.prototype.translate = function(e) {
             n.prototype.translate = function(e) {
                 this.position.add(e),
                 this.position.add(e),
-                this.floorPosition.add(e)
+                this.floorPosition.add(e),
+                this.baseFloorPosition && this.baseFloorPosition.add(e)
             }
             }
             ,
             ,
             n.prototype.findClosestMidtpointPanoTo = function(e) {
             n.prototype.findClosestMidtpointPanoTo = function(e) {
@@ -20511,6 +20518,18 @@ window.Modernizr = function(n, e, t) {
                 this.currentPanoMarker.mesh.parent || e.add(this.currentPanoMarker.mesh)
                 this.currentPanoMarker.mesh.parent || e.add(this.currentPanoMarker.mesh)
             }
             }
             ,
             ,
+            n.prototype.shouldHideCpmAtCurrentPano = function() {
+                return this.player && this.player.mode === a.PANORAMA && this.player.currentPano && this.player.currentPano.isAligned()
+            }
+            ,
+            n.prototype.syncCpmVisibility = function() {
+                if (!this.currentPanoMarker || !this.currentPanoMarker.mesh)
+                    return;
+                var e = this.shouldHideCpmAtCurrentPano();
+                this.currentPanoMarker.mesh.visible = !e,
+                e && this.currentPanoMarker.mesh.material && this.currentPanoMarker.mesh.material.uniforms && this.currentPanoMarker.mesh.material.uniforms.opacity && (this.currentPanoMarker.mesh.material.uniforms.opacity.value = 0)
+            }
+            ,
             n.prototype.placeCpm = function() {
             n.prototype.placeCpm = function() {
                 if (c.path.mapGuides && this.player.currentPano && this.player.currentPano.isAligned()) {
                 if (c.path.mapGuides && this.player.currentPano && this.player.currentPano.isAligned()) {
                     var e = this.player.currentPano.floor;
                     var e = this.player.currentPano.floor;
@@ -20518,19 +20537,22 @@ window.Modernizr = function(n, e, t) {
                     e.add(this.currentPanoMarker.mesh)),
                     e.add(this.currentPanoMarker.mesh)),
                     this.currentPanoMarker.mesh.position.copy(this.player.currentPano.floorPosition).sub(e.position),
                     this.currentPanoMarker.mesh.position.copy(this.player.currentPano.floorPosition).sub(e.position),
                     this.currentPanoMarker.mesh.position.y += this.pathHeight() ,
                     this.currentPanoMarker.mesh.position.y += this.pathHeight() ,
-                    this.currentPanoMarker.placed = !0
+                    this.currentPanoMarker.placed = !0,
+                    this.syncCpmVisibility()
                 } else
                 } else
                     this.popOutCpm()
                     this.popOutCpm()
             }
             }
             ,
             ,
             n.prototype.fadeInCpm = function(e) {
             n.prototype.fadeInCpm = function(e) {
-                //this.player.mode === a.PANORAMA && this.player.currentPano && !this.player.currentPano.isAligned() || c.path.mapGuides && this.currentPanoMarker.placed && p.start(u.property(this.currentPanoMarker.mesh.children[0].material/* .uniforms.opacity */, "opacity", 1), e)
-                this.player.mode === a.PANORAMA && this.player.currentPano && !this.player.currentPano.isAligned() || c.path.mapGuides && this.currentPanoMarker.placed && p.start(u.property(this.currentPanoMarker.mesh.material.uniforms.opacity, "value", 1), e)
+                if (this.shouldHideCpmAtCurrentPano())
+                    return void this.syncCpmVisibility();
+                c.path.mapGuides && this.currentPanoMarker.placed && (this.currentPanoMarker.mesh.visible = !0,
+                p.start(u.property(this.currentPanoMarker.mesh.material.uniforms.opacity, "value", 1), e))
             }
             }
             ,
             ,
             n.prototype.fadeOutCpm = function(e) {
             n.prototype.fadeOutCpm = function(e) {
-                //p.start(u.property(this.currentPanoMarker.mesh.children[0].material/* .uniforms.opacity */, "opacity", 0), e)
-                p.start(u.property(this.currentPanoMarker.mesh.material.uniforms.opacity, "value", 0), e)
+                this.currentPanoMarker && this.currentPanoMarker.mesh && this.currentPanoMarker.mesh.material && this.currentPanoMarker.mesh.material.uniforms && this.currentPanoMarker.mesh.material.uniforms.opacity && (this.currentPanoMarker.mesh.material.uniforms.opacity.value = 0),
+                this.syncCpmVisibility()
             }
             }
             
             
            
            
@@ -23525,7 +23547,10 @@ window.Modernizr = function(n, e, t) {
                 if(this.mode != "panorama")return;
                 if(this.mode != "panorama")return;
                 this.model.panos.list.forEach((pano)=>{
                 this.model.panos.list.forEach((pano)=>{
                     if(!pano.marker)return;
                     if(!pano.marker)return;
-                    pano.marker.material.visible = !!pano.neighbourPanos[this.currentPano.id];
+                    var isCurrent = pano.id == this.currentPano.id;
+                    var isNeighbour = !!pano.neighbourPanos[this.currentPano.id];
+                    pano.marker.material.visible = !isCurrent && isNeighbour;
+                    pano.marker.material.opacity = !isCurrent && isNeighbour ? _settings.panorama.markerOpacity : 0;
                 })
                 })
             }
             }
             ,
             ,

+ 192 - 0
js/manage.js

@@ -3038,3 +3038,195 @@ var g_onePregix = "https://bigscene.4dage.com/" //对应一代  http://www.4dmod
 var g_version = manage.number("version");
 var g_version = manage.number("version");
 g_version === "one" ? g_Prefix = g_onePregix : '';
 g_version === "one" ? g_Prefix = g_onePregix : '';
 
 
+(function() {
+    var ZERO_EPS = 1e-6;
+    var DEFAULT_LIFT = 0.1;
+
+    function toNumber(value, fallback) {
+        var num = parseFloat(value);
+        return isFinite(num) ? num : fallback;
+    }
+
+    function roundValue(value) {
+        return Math.round(value * 1000000) / 1000000;
+    }
+
+    window.PuckHeightHelper = {
+        zeroEps: ZERO_EPS,
+        defaultLift: DEFAULT_LIFT,
+        normalizeOverrideValue: function(raw) {
+            if (raw && typeof raw === "object") {
+                return {
+                    x: roundValue(toNumber(raw.x, 0)),
+                    y: roundValue(toNumber(raw.y, 0)),
+                    z: roundValue(toNumber(raw.z, 0))
+                };
+            }
+            return {
+                x: 0,
+                y: roundValue(toNumber(raw, 0)),
+                z: 0
+            };
+        },
+        isZeroVector: function(vec) {
+            vec = this.normalizeOverrideValue(vec);
+            return Math.abs(vec.x) <= ZERO_EPS && Math.abs(vec.y) <= ZERO_EPS && Math.abs(vec.z) <= ZERO_EPS;
+        },
+        cleanOverrideValue: function(raw) {
+            var vec = this.normalizeOverrideValue(raw);
+            if (this.isZeroVector(vec)) {
+                return null;
+            }
+            if (Math.abs(vec.x) <= ZERO_EPS && Math.abs(vec.z) <= ZERO_EPS) {
+                return roundValue(vec.y);
+            }
+            return {
+                x: Math.abs(vec.x) > ZERO_EPS ? roundValue(vec.x) : 0,
+                y: Math.abs(vec.y) > ZERO_EPS ? roundValue(vec.y) : 0,
+                z: Math.abs(vec.z) > ZERO_EPS ? roundValue(vec.z) : 0
+            };
+        },
+        normalizeConfig: function(raw) {
+            var config = {
+                globalDelta: 0,
+                overrides: {}
+            };
+            raw = raw || {};
+            config.globalDelta = toNumber(raw.globalDelta, 0);
+            if (raw.overrides && typeof raw.overrides === "object") {
+                for (var id in raw.overrides) {
+                    if (!raw.overrides.hasOwnProperty(id)) {
+                        continue;
+                    }
+                    var delta = this.normalizeOverrideValue(raw.overrides[id]);
+                    if (!this.isZeroVector(delta)) {
+                        config.overrides[id] = delta;
+                    }
+                }
+            }
+            return config;
+        },
+        getConfig: function() {
+            window.DATA = window.DATA || {};
+            window.DATA.puckHeight = this.normalizeConfig(window.DATA.puckHeight);
+            return window.DATA.puckHeight;
+        },
+        cleanConfig: function(raw) {
+            var config = this.normalizeConfig(raw);
+            var cleaned = {
+                globalDelta: Math.abs(config.globalDelta) > ZERO_EPS ? roundValue(config.globalDelta) : 0,
+                overrides: {}
+            };
+            for (var id in config.overrides) {
+                if (!config.overrides.hasOwnProperty(id)) {
+                    continue;
+                }
+                var cleanedOverride = this.cleanOverrideValue(config.overrides[id]);
+                if (cleanedOverride) {
+                    cleaned.overrides[id] = cleanedOverride;
+                }
+            }
+            if (!cleaned.globalDelta && Object.keys(cleaned.overrides).length === 0) {
+                return null;
+            }
+            return cleaned;
+        },
+        getOverrideOffset: function(panoOrId, config) {
+            config = this.normalizeConfig(config);
+            var id = typeof panoOrId === "string" ? panoOrId : panoOrId && panoOrId.id;
+            if (id && config.overrides.hasOwnProperty(id)) {
+                return this.normalizeOverrideValue(config.overrides[id]);
+            }
+            return {
+                x: 0,
+                y: 0,
+                z: 0
+            };
+        },
+        getEffectiveOffset: function(panoOrId, config) {
+            config = this.normalizeConfig(config);
+            var override = this.getOverrideOffset(panoOrId, config);
+            return {
+                x: roundValue(override.x),
+                y: roundValue((config.globalDelta || 0) + override.y),
+                z: roundValue(override.z)
+            };
+        },
+        getEffectiveDelta: function(panoOrId, config) {
+            return this.getEffectiveOffset(panoOrId, config).y;
+        },
+        captureBaseFloorPosition: function(model) {
+            if (!model || !model.panos || !model.panos.forEach) {
+                return;
+            }
+            model.panos.forEach(function(pano) {
+                if (pano && pano.floorPosition && !pano.baseFloorPosition) {
+                    pano.baseFloorPosition = pano.floorPosition.clone();
+                }
+            });
+        },
+        applyToPano: function(pano, config) {
+            if (!pano) {
+                return;
+            }
+            if (!pano.floorPosition && pano.baseFloorPosition) {
+                pano.floorPosition = pano.baseFloorPosition.clone();
+            }
+            if (!pano.floorPosition) {
+                return;
+            }
+            if (!pano.baseFloorPosition) {
+                pano.baseFloorPosition = pano.floorPosition.clone();
+            }
+            pano.floorPosition.copy(pano.baseFloorPosition);
+            var offset = this.getEffectiveOffset(pano, config);
+            pano.floorPosition.x += offset.x;
+            pano.floorPosition.y += offset.y;
+            pano.floorPosition.z += offset.z;
+            if (typeof pano.placeMarker === "function") {
+                pano.placeMarker();
+            }
+        },
+        applyToModel: function(model, config) {
+            if (!model || !model.panos || !model.panos.forEach) {
+                return;
+            }
+            config = this.normalizeConfig(config);
+            this.captureBaseFloorPosition(model);
+            model.panos.forEach(function(pano) {
+                window.PuckHeightHelper.applyToPano(pano, config);
+            });
+        },
+        getRaycastTargets: function(pano) {
+            if (pano && pano.floor && pano.floor.collider && pano.floor.collider.children && pano.floor.collider.children.length) {
+                return pano.floor.collider.children;
+            }
+            if (pano && pano.model && pano.model.colliders && pano.model.colliders.length) {
+                return pano.model.colliders;
+            }
+            return [];
+        },
+        raycastGroundPoint: function(pano) {
+            if (!window.THREE || !pano || !pano.position) {
+                return null;
+            }
+            var targets = this.getRaycastTargets(pano);
+            if (!targets.length) {
+                return null;
+            }
+            var raycaster = new THREE.Raycaster(pano.position.clone(), new THREE.Vector3(0, -1, 0));
+            var hits = raycaster.intersectObjects(targets, true);
+            return hits.length ? hits[0].point.clone() : null;
+        },
+        computeAutoDelta: function(pano, lift) {
+            if (!pano || !pano.baseFloorPosition) {
+                return null;
+            }
+            var point = this.raycastGroundPoint(pano);
+            if (!point) {
+                return null;
+            }
+            return roundValue(point.y + toNumber(lift, DEFAULT_LIFT) - pano.baseFloorPosition.y);
+        }
+    };
+})();