浏览代码

更新一波

xzw 3 年之前
父节点
当前提交
8dbb257bb2
共有 6 个文件被更改,包括 495 次插入492 次删除
  1. 27 7
      edit.html
  2. 17 6
      js/Hot.js
  3. 134 24
      js/edit.js
  4. 29 225
      js/main_2020_edit.js
  5. 40 229
      js/main_2020_show.js
  6. 248 1
      js/manage.js

+ 27 - 7
edit.html

@@ -927,6 +927,7 @@
                                     打开模型线框(临时)
                                 </label>
                             </ul>
+                            
                             <div class="itemTitle">
                                 <span>热点默认大小 (初始值为1)</span>
                             </div>
@@ -934,6 +935,14 @@
                                 <input class="" type="number" placeholder="请输入热点大小比例" value="1" max="100" min="0.1"
                                     step="0.1">
                             </ul>
+                            
+                            <ul class="switch clearfix   ">
+                                <label><input  id="autoAdjustHotScale" class="mui-switch mui-switch-animbg" type="checkbox">
+                                    自适应热点大小 
+                                </label>
+                            </ul>
+                            <label class="remark " >注: 自适应热点大小仅对贴图样式为“闪烁”的热点生效 </label>
+                             
                         </li>
                         <li id="hotVisible">
                             <div class="buttons">
@@ -1483,8 +1492,7 @@
                                 <label><input class="mui-switch mui-switch-animbg" type="checkbox">
                                     启用瞬间过渡
                                 </label>
-                            </ul>
-                             
+                            </ul> 
                             <div class="itemTitle">
                                 <span>瞬间过渡速度</span>
                             </div>
@@ -1493,6 +1501,13 @@
                                 <span>行走过渡速度</span>
                             </div>
                             <div id="tourWalkSpeed"></div>
+                            <div class="itemTitle">
+                                <span>片段原地停留时间(秒)</span>
+                            </div>
+                            <ul name='rotTime' class="clearfix ">
+                                <input class="" type="number" placeholder="" value="" max="1000" min="0" step="0.1">
+                            </ul>
+                            <div class="remark">注:有音乐的片段以音乐时长来分配时间,不以此项</div>
                         </li>
                         
                         
@@ -1614,13 +1629,13 @@
                                         </ul>  
                                     </li>
                                     <li> 
-                                       
                                         <div class="itemTitle">
                                             <span>原地停留时间(秒)</span>
                                         </div>
                                         <ul name='rotTime' class="clearfix ">
-                                            <input class="" type="number" placeholder="若不填写,默认2秒" value="1" max="1000" min="0" step="0.1">
-                                        </ul>        
+                                            <input class="" type="number" placeholder="若不填写,同外层" value="1" max="1000" min="0" step="0.1">
+                                        </ul>    
+                                        <div class="remark">注:此设置的权重高于音乐,即设置后无视音乐时长</div>
                                         <ul name="rotSwitch" class="switch clearfix  ">
                                             <label><input class="mui-switch mui-switch-animbg" type="checkbox">
                                                 开启旋转 
@@ -1661,10 +1676,15 @@
                 <div class="panoVisible content hide">
                     <ul class="view-setting">
                         <li>
-                            <div class="itemTitle"><span>漫游可行</span></div>
-                            <div class="remark">通过设置漫游可行,进一步优化在漫游时出现的体验;例如,您在漫游时,出现穿透房间的情况。</div>
+                            <div class="itemTitle"><span>漫游可行</span></div> 
                             <div class="remark">点击“保存当前设置”后展示页面立即生效。</div>
                         </li>
+                        <li> 
+                            <div class="remark">如果点位过多,可以点击自动计算,以免去人工选择的时间,避免大片穿墙现象。</div>
+                            <div class="buttons">
+                                <button class="innerBtn cancel" name='autoCompute'>自动计算</button>
+                            </div>
+                        </li>
                     </ul>
                 </div>
                 

+ 17 - 6
js/Hot.js

@@ -28,7 +28,7 @@ window.initHot = function(model){
         opacity: 0.8,
         side:THREE.DoubleSide
     })
-    
+    var autoSizeInfo = {minSize : 120,  maxSize : 600,   nearBound : 1 , farBound :  15}
 
     var hotGroup = new THREE.Object3D;  hotGroup.name = "hotGroup"
     model.add(hotGroup);   model.hotGroup = hotGroup
@@ -930,10 +930,21 @@ window.initHot = function(model){
                 this.quaternion.copy(player.camera.quaternion)
             }
             
-            
+            this.updateScale()
         }
                     
-                    
+        updateScale(e, t) {//自适应调节大小 
+            if(!DATA.autoAdjustHotScale || this.texType != 'shine' )return
+            //let renderSize = player.sceneRenderer.renderer.domElement 
+            let renderSize = player.sceneRenderer.renderer.getSize()
+            
+            var scale = convertTool.getScaleForConstantSize($.extend(autoSizeInfo,{
+                camera:player.camera,  resolution:{x:renderSize.width, y:renderSize.height},
+                position: this.position.clone() ,
+            }))
+            this.plane.scale.set(scale,scale,scale)
+            
+        }                
 
 
         switchPlay(state){//手动播放暂停 
@@ -1070,7 +1081,7 @@ window.initHot = function(model){
                 
                 
             var s = t.model.panos.sortByScore(i, n);
-            console.log(s)
+             
             return s && 0 < s.length && s[0].pano
         }
          
@@ -1337,7 +1348,7 @@ window.initHot = function(model){
              
             if(type == 'photo'){
                 if(this.photoHasRequestLoad || this.texType != 'photo')return;
-                console.log('overlay beginDownload : ' + this.sid)
+                //console.log('overlay beginDownload : ' + this.sid)
                 
                  
                 /* this.material_.map =  */Texture.load(this.info.texSrc, (tex)=>{ 
@@ -1353,7 +1364,7 @@ window.initHot = function(model){
                         if(e.info.texSrc == this.info.texSrc && e.info.texType == type  ){ 
                             e.material_.color.set("#FFFFFF") 
                             e.material_.opacity = 1;
-                            console.log('overlay loaded: ' + e.sid + " - " + this.info.texSrc.split('/').pop());
+                            //console.log('overlay loaded: ' + e.sid + " - " + this.info.texSrc.split('/').pop());
                         
                         
                              

+ 134 - 24
js/edit.js

@@ -123,6 +123,12 @@ EditTools.prototype.init = function() {
         
     }
     
+    
+    $(".toolRight .panoVisible [name=autoCompute]").on('click',()=>{
+        VisiSet.resetPanosVisiByModel()
+    }) 
+    
+    
 
 }
 //点击的时候激活状态
@@ -229,8 +235,8 @@ EditTools.prototype.initSaveAll = function() {
                 return dom.data
             }) */
             
-            
-            
+            let tourRotTime = parseFloat($('.toolRight .snapTour [name="rotTime"] input').val()) 
+            isNaN(tourRotTime) && (tourRotTime = '') 
 
             var info = {
                 name: $('#pjtName').val(),
@@ -248,6 +254,9 @@ EditTools.prototype.initSaveAll = function() {
                 /************************************** 方奕卓 场景可配置项 ******************************************/
                 hotImageScale: $("#hotImgScale").is(':checked'),
                 // 热点图片可放大
+                
+                autoAdjustHotScale : $("#autoAdjustHotScale").is(':checked'),
+                
                 hideFloorMarker: $("#hideFloorMarker").is(':checked'),
                 // 地面标记
                 hideMouseMarker: $("#hideMouseMarker").is(':checked'),
@@ -261,7 +270,7 @@ EditTools.prototype.initSaveAll = function() {
                 momentTour: $('#tourSwitch input').is(':checked') ? 'black' : 'walk',
                 tourBlackSpeed : that.editGuide.scroller.tourBlackSpeed.value,
                 tourWalkSpeed : that.editGuide.scroller.tourWalkSpeed.value,
-                
+                tourRotTime,
                 
                 // 导览瞬间过渡
                 showHotListSta: $('#hotListSwitch').is(':checked'),
@@ -887,6 +896,8 @@ Hotpoint.prototype.init = function() {
     })
     
     
+    $("#autoAdjustHotScale")[0].checked = !!DATA.autoAdjustHotScale;
+    
     
     //动画
     
@@ -3285,10 +3296,19 @@ EditGuide.prototype.init = function(data, data2) {
             e.target.value = s   
             that.editingItemLi.tourData.rotTime = s
         })
+    } 
+    {////////////////
+        let ui = $('.toolRight .snapTour [name="rotTime"] input')
+        let min = parseFloat(ui.attr('min'));
+        let max = parseFloat(ui.attr('max'));
+        ui.on("change", function(e) {  
+            var s = THREE.Math.clamp(parseFloat(e.target.value), min, max)
+            if(isNaN(s))s = ''
+            e.target.value = s  
+        })
+        ui.val(DATA.tourRotTime)
     }
     
-    
-    
     {
         this.scroller = { 
             tourBlackSpeed : new SlideBar({
@@ -4875,26 +4895,33 @@ var VisiSet = {
         this.changeBtn.removeClass('hide')
     },
 
-    saveLastPanoVi: function() {
+    saveLastPanoVi: function(o={}) {
         //保存刚设置过的pano
         var change = [];
-        for (var r in this.panoVLines) {
-            var line = this.panoVLines[r];
-            if (line.name.indexOf("new") > -1 && line.visible) {
-                //新设置为visible且没有取消 
-                change.push({
-                    type: "add",
-                    id: r
-                })
+        
+        /* if(o.type == 'autoCompute'){
+            
+        }else{ */
+            for (var r in this.panoVLines) {
+                var line = this.panoVLines[r];
+                if (line.name.indexOf("new") > -1 && line.visible) {
+                    //新设置为visible且没有取消 
+                    change.push({
+                        type: "add",
+                        id: r
+                    })
 
-            } else if (line.name.indexOf("new") == -1 && !line.visible) {
-                //旧的且已经取消
-                change.push({
-                    type: "sub",
-                    id: r
-                })
+                } else if (line.name.indexOf("new") == -1 && !line.visible) {
+                    //旧的且已经取消
+                    change.push({
+                        type: "sub",
+                        id: r
+                    })
+                }
             }
-        }
+        /* } */
+        
+        
 
         if (change.length) {
             //添加双向的neighbour:
@@ -5440,9 +5467,61 @@ var VisiSet = {
                 console.log(e)
             }
         })
-    }
+    },
+    
+    
+    
+    resetPanosVisiByModel: function() {//一键计算所有漫游可行 (计算后自动连接,但不保存)
+     
+        $('.waiting').addClass('showloading');
+        
+        let begin = ()=>{
+            this.pauseSetPanoVisible("unsaved")
+            
+        
+            var ifBlock = function(panoA, panoB ){
+                var A = panoA.position.clone();
+                var B = panoB.position.clone(); 
+                return !!convertTool.ifIntersectChunks(A, B, {})
+            }
+            
+                    
+            player.model.panos.list.forEach(pano1=>{
+                this.SetOnePanoVisible(pano1)//开始设置pano1
+                
+                player.model.panos.list.forEach(pano2=>{
+                    if(pano1 == pano2)return
+                    if(pano1.id == '9'&& pano2.id == '0'){
+                        console.log(1)
+                    }
+                    var visiNew = !ifBlock(pano1,pano2)
+                    var visiOld = !!(this.panoVLines[pano2.id] && this.panoVLines[pano2.id].visible)
+                    if(visiNew != visiOld){
+                        //console.log('修改 '+pano1.id+'-'+pano2.id)
+                        this.dealPanoVisible(pano2.id)//修改
+                    }
+                    
+                })
+                this.pauseSetPanoVisible('unsaved')//修改pano1结束
+            })
+            
+            $('.waiting').removeClass('showloading');
+            manage.showInfo("修改成功,可以点击漫游点查看。点击保存当前设置后生效。")
+        }
+        
+        setTimeout(()=>{
+            if(this.setPanoVisible){
+                begin()
+            }
+        },100)
+    },
+    
+    
+    
+    
+    
     //========热点可见性==============  
-    ,
+    
     beginSetTagVisible: function() {
         if (this.setTagVisible)
             return;
@@ -5629,7 +5708,38 @@ var VisiSet = {
             this.meshGroup.remove(this.panoVLines[i]);
             delete this.panoVLines[i];
         }
-    }
+    },
+    //------------
+    
+    
+    
+    
+    
+    /* resetTagVisiByModel : function(){//自动计算所有热点的可视  当模型修改后所有的热点可视都会重新自动计算(用户的设置将被覆盖)
+		var visiTags = [];
+		for(var i in objects.tagManager.tags){
+			var tag = objects.tagManager.tags[i];
+			if(tag.state == "videoPanoFlag")continue;
+			var visiblePanos = tag.getVisiblePanos(); 
+			visiTags.push({sid:tag.sid, value:visiblePanos})
+		}
+        
+        return visiTags;
+		
+        
+    },
+    afterResetTagVisibles : function(visiTags){
+        visiTags.forEach((info)=>{
+            objects.tagManager.tags[info.sid].setVisiblePanos(info.value); 
+        })
+        if(objects.player.mode == "panorama")objects.tagManager.updateVisible("panorama");
+        
+    },
+	resetVisiblesByModel : function(){//自动计算所有热点和漫游点的可视
+	 
+		this.resetTagVisiByModel()
+	 
+	} */
 
 }
 

+ 29 - 225
js/main_2020_edit.js

@@ -1,212 +1,5 @@
-window.common = null;
-window.MathLight = null;
-window.math = null
  
  
-var dealMap = (map)=>{//使不resize  when   image is not power of two
-    map.wrapS = map.wrapT = THREE.ClampToEdgeWrapping; 
-    map.minFilter = THREE.LinearFilter;
-    map.magFilter = THREE.LinearFilter;
-    map.generateMipmaps = true;  
-    
-}  
- 
-
-
-/* var sortByScore = function(list,g_tourAudio request, rank) {
-    var i = common.filterAll(list, request);
-    return 0 === i.length ? null : i = i.map(function(e) {
-        return {
-            item: e,
-            score: rank.reduce(function(t, i) {
-                return t + i(e);
-            }, 0)
-        };
-    }).sort(function(e, t) {
-        return t.score - e.score;
-    });
-};
- */
-var getTransformSid = function(){
-    var name
-    if(player.mode == 'panorama'){
-        name = player.currentPano ? player.currentPano.id : 'outside'
-    }else{
-        name = 'outside'
-    }
-    return name
-} 
- 
-var convertTool = { 
-	getPos2d : function(point, camera, dom){//获取一个三维坐标对应屏幕中的二维坐标
-		var camera = camera || player.camera;
-		var dom = dom || player.domElement;
-		var pos = point.clone().project(camera)	//比之前hotspot的计算方式写得简单  project用于3转2(求法同shader); unproject用于2转3 :new r.Vector3(e.x, e.y, -1).unproject(this.camera);
-		
-		var x,y;
-		x = (pos.x + 1) / 2 * dom.clientWidth;
-		y = (1 - (pos.y + 1) / 2) * dom.clientHeight; 
-  
-		var inSight = x <= dom.clientWidth &&  x >= 0    //是否在屏幕中   
-					&& y <= dom.clientHeight &&  y >= 0 
-	 
-	
-		return {
-			pos: new THREE.Vector2(x,y),  // 屏幕像素坐标
-			vector:  pos,   //(范围 -1 ~ 1)
-			trueSide : pos.z<1, //trueSide为false时,即使在屏幕范围内可见,也是反方向的另一个不可以被渲染的点   参见Tag.update
-			inSight : inSight	//在屏幕范围内可见
-		};
-	},
-
-	ifShelter: function(pos3d){//检测某点在视线中是否被mesh遮挡 
-		var ori = player.position
-        var dir = pos3d.clone().sub(ori).normalize()
-        var ray = new THREE.Raycaster(ori, dir) //由外向里 因为模型从内侧是可见的所以从外侧
-		
-		/* if(config.isEdit && publicObjectSet.editor.mainDesign.editing){
-			var o = ray.intersectObjects(publicObjectSet.editor.mainDesign.wallMeshes);
-		}else{ */
-			var o = ray.intersectObjects(player.model.colliders);
-		//} 
-		var len = pos3d.distanceTo(ori);
-		if (o && o.length) {
-			for(var i=0;i<o.length;i++){
-				if(o[i].distance < len){  return true;  }//有遮挡
-			} 
-		} 
-	},
-    
-    
-    /* 
-        拖拽时,获取鼠标在拖拽面上的位置(需要借助另一个intersectPlane面来计算,即和相机方向一样的面,可保证铺满屏幕)
-        但是不一定能获取到,比如鼠标射线不朝向拖拽面时,即使获取也会是一个意外的反方向的交点。
-	 */
-	getPosAtPlane : function(pos, info/* , mouse, camera */){ //pos:与intersectPlane的交点 见笔记
-		var A = pos; 
-        var player = player;      
-        var mouse = player.mouse;
-        var O = new THREE.Vector3(mouse.x, mouse.y, -1).unproject(player.camera);
-		
-		
-		if(info.y != void 0){//地面线的
-        
-            var y = info.y; 
-            
-            if(player.mode == "floorplan"/*  ||  Math.abs(O.x-pos.x)<0.0001 && Math.abs(O.z-pos.z)<0.0001) */){
-            //intersectPlane和地面平行,无交点
-                var x = pos.x, z = pos.z;
-            
-            }else{
-             
-                if(y<player.camera.position.y && O.y <= A.y /* || y>player.camera.position.y && O.y >= A.y  */)return null;  //鼠标射线向上。因为相机一定位于地面以上(地面不会抬高到相机上吧?),所以无交点。
-                if(O.y == A.y){console.log('一样??');return;}
-                if(A.y == y){console.log('一样2??');return;}
-                var r = (O.y-y)/(A.y-y);
-                var x = (r*A.x-O.x)/(r-1);
-                var z = (r*A.z-O.z)/(r-1); 
-			}
-		}else{//垂直的也有越过消失点以后反向变化的情况,但使用时影响不大
-			var N = info.normalVec;
-			var P = info.pullPos;
-			if(N.y != 0 ){console.log('N.y != 0');return;} //仅仅支持垂直于地面的的墙壁,目前都是
-			if(O.z==A.z){console.log('O.z==A.z?');return;}
-			if(N.z!=0 && N.x != 0){//直接用这个通用的也可以,支持斜线的墙
-				//console.log('N.z==0 && N.x == 0?');  
-				var c = ( N.x*(A.x-O.x) + N.y*(A.y-O.y) + N.z*(A.z-O.z));
-				if(c == 0){console.log("分母为0?? return;");return;} 
-				var t = -((N.x*O.x + N.y*O.y + N.z*O.z) - (P.x*N.x + P.y*N.y + P.z*N.z) ) / c
-				var x = t * (A.x - O.x) + O.x;
-				var y = t * (A.y - O.y) + O.y;
-				var z = t * (A.z - O.z) + O.z;
-				/*原理: 已知空间直线L:(x-a)/m=(x-b)/n=(z-c)/p和空间平面π:Ax+By+Cz+D=0;
-				求直线L与平面π的交点的坐标。
-				把直线方程改写成参数形式:设(x-a)/m=(x-b)/n=(z-c)/p=t;
-				则x=mt+a;y=nt+b;z=pt+c;代入平面π的方程得:
-				A(mt+a)+B(nt+b)+C(pt+c)+D=0
-				由此解得t=-(Aa+Bb+Cc+D)/(Am+Bn+Cp)
-				再代入参数方程即得交点的坐标(x,y,z). */
-			}else if(N.x ==0 ){ //z与pullPos相等
-				var z = P.z;
-				if(O.y == A.y){console.log('一样??');return;}
-				if(A.y == y){console.log('一样2??');return;}
-                if(A.z == z){console.log('一样3??');return;}
-				var r = (O.z-z)/(A.z-z);
-				var x = (r*A.x-O.x)/(r-1);
-				var y = (r*A.y-O.y)/(r-1);
-			}else if(N.z == 0){//x与pullPos相等
-				var x = P.x;
-				if(O.y == A.y){console.log('一样??');return;}
-				if(A.y == y){console.log('一样2??');return;}
-                if(A.x == x){console.log('一样3??');return;}
-				var r = (O.x-x)/(A.x-x);
-				var y = (r*A.y-O.y)/(r-1);
-				var z = (r*A.z-O.z)/(r-1);
-			}
-		}   
-		
-		return new THREE.Vector3(x,y,z);
-	},
-
-
-	
-	getMouseIntersect : function(camera, meshes, mouse){//获取鼠标和meshes交点
-		var raycaster = new THREE.Raycaster; 
-		camera.updateMatrixWorld(); 
-		var origin = new THREE.Vector3(mouse.x,mouse.y,-1).unproject(camera)
-		  , end = new THREE.Vector3(mouse.x,mouse.y,1).unproject(camera); 
-		var dir = end.sub(origin).normalize() 
-		raycaster.set(origin, dir);
-		var n = raycaster.intersectObjects(meshes);
-		if (0 === n.length)
-			return null;
-		return n[0];
-		
-	},
-	ifIntersectChunks : function(A,B,options={}){//获取某个线段/射线和meshes的交点 
-		var dir = B.clone().sub(A).normalize();
-		var len = options.InfinityLen ? Infinity :  A.distanceTo(B) + (options.extLen||0);
-		var ray = new THREE.Raycaster(A.clone(), dir, 0, len);
-          
-		var o = ray.intersectObjects(options.model || player.model.colliders);
-		if (o && o.length)return o;
-		  
-		if(options.throughWidth){ //允许最小宽度,防止穿过极小的缝隙导致撞墙感
-			var normal = math.getNormal({points:[{x:A.x, y:A.z},{x:B.x, y:B.z}]});//线段法线
-			normal.multiplyScalar(options.throughWidth)
-			var normalVec3 = new THREE.Vector3(normal.x, 0, normal.y);
-			
-			var A2 = A.clone().add(normalVec3)
-			ray.set(A2, dir);  
-			var o2 = ray.intersectObjects(options.model || player.model.colliders);
-			ray.set(A.clone().add(normalVec3.negate()), dir);
-			if (o2 && o2.length)return o2;
-			var o3 = ray.intersectObjects(options.model || player.model.colliders);
-			if (o3 && o3.length)return o3; 
-		} 
-		return null;
-	},
-	getPosAtSphere : function(pos3d, toPanoPos){
-		var dir = pos3d.clone().sub(toPanoPos); 
-		dir.normalize();//然后计算在球中
-		dir.multiplyScalar(Constants.skyRadius);   
-		dir.add(toPanoPos); 
-		return dir;
-	} 
-
-}
-
- 
-
-
-var dom = {
-    getOffset: function(e, t, i) {
-        for (left = "left" == e ? t.offsetLeft : t.offsetTop,
-        i = i || $("body")[0]; (t = t.offsetParent) && t != i; )
-            left += "left" == e ? t.offsetLeft : t.offsetTop;
-        return left
-    }
-};
 if (function() {
     "use strict";
     function o(e, t) {
@@ -4592,11 +4385,11 @@ function o(a, s, l) {
                 })
             }
             ,
-            t.prototype.checkAndHandleWalkingtourInterruption = function(e) {
-                return e === c.WALK && (this.interrupt(p.NONE),
+            t.prototype.checkAndHandleWalkingtourInterruption = function(e) {//快速停止。 改:去掉判断nextWarpStyle,因为这个属性改乱了,导致点击停止按钮不执行
+                return /* e === c.WALK && ( */this.interrupt(p.NONE),
                 this.pauseWalkingSection(),
                 this.player.fastForwardActivePanoFlight(),
-                !0)
+                !0/* ) */
             }
             ,
             t.prototype.handlePlayerMove = function(e) {
@@ -4840,7 +4633,7 @@ function o(a, s, l) {
                           , s = null
                           , l = null;
                         if (a.isPano()) {  
-                            var o1 = this.getMomentTour(this.destinationItem)   //window.DATA.momentTour || "walk";
+                            var o1 = e ? 'black' : this.getMomentTour(this.destinationItem)   //window.DATA.momentTour || "walk";
                             l = this.player.warpToPanoByHeroIndex.bind(this.player, this.destinationItem, g.Show, f.Slow, o1, !0, i, this.actionComplete.bind(this)),
                             s = this.arrivedAtDestination.bind(this, !0)
                              
@@ -4938,7 +4731,7 @@ function o(a, s, l) {
                     this.clearWalkingSectionPaused(),
                     this.setDestinationItem(e),
                     this.useSpecialTransition("Hilight"),
-                    this.goToDestination(),
+                    this.goToDestination(true),//add true
                     l.trackAlways("reach_highlight", {
                         reach_source: "thumb"
                     })
@@ -14355,6 +14148,10 @@ function o(a, s, l) {
                                     window._settings.warp.flyTime = settings.flyTime 
                                 } */
                                 
+                                if(DATA.tourRotTime == '' || DATA.tourRotTime == void 0){
+                                    DATA.tourRotTime = settings.tourRotTime; //默认停留2秒
+                                }
+                                 
                             }
                                     
                             
@@ -18059,8 +17856,12 @@ function o(a, s, l) {
             }
             ,
             r.prototype.build1 = function() {
-                this.floor = this.floor || this.model.floors.get(this.floorIndex) || this.raycastToFindFloor() || this.model.getFloorAtPoint(this.position),
-                this.floor.addPano(this),
+                this.floor = this.floor || this.model.floors.get(this.floorIndex) || (this.model.floors.list.length == 1 ? this.model.floors.list[0] : this.raycastToFindFloor()) || this.model.getFloorAtPoint(this.position), //改
+                
+                 
+                
+                this.floor.addPano(this)
+                
                 this.floorPosition = this.floorPosition || this.raycastFloorPosition(),
                 this.neighbourPanos = this.neighbourPanos || this.findNeighourPanos(),
                 a.colorMarkerByFloor && this.marker && this.marker.material.color.set(this.floor.debugColor)
@@ -22501,23 +22302,26 @@ function o(a, s, l) {
             t.prototype.tourInterlude = function(e, t) {
                 this.history.invalidate(),
                 this.path.discardSlow();
-                var timeEachItem = 2e3 / (DATA.tourWalkSpeed + DATA.tourBlackSpeed) * 200 //预估时间假设每个item飞的时间
+                var defaultRotTime = DATA.tourRotTime * 1000
+                var timeEachItem = 2e3 / (DATA.tourWalkSpeed + DATA.tourBlackSpeed) * 200 //预估时间假设每个item飞的时间(如果距离远就少了)
                  
                 var currentLocation = this.model.heroLocations[this.director.currentItem[0]] 
                 var rotTime
                 if(currentLocation.rotTime == void 0 || currentLocation.rotTime == ''){
                     var restChildCount = currentLocation.heroLocations ? (currentLocation.heroLocations.length-this.director.currentItem[1]-1) : 0
-                    var audioObj = SoundManager.list.find(e=>e.name == 'tour')
-                    var current = audioObj.audio.currentTime * 1e3 // || 0  //g_tourAudio ? 1e3 * g_tourAudio.currentTime : 0
-                    rotTime = currentLocation && currentLocation.musicInfo.music ? currentLocation.musicInfo.time - current : timeEachItem;  
-                    
-                    if(restChildCount){//如果当前folder中还有剩下的item,平分一下时间
-                        
-                        var rotTime = (rotTime-timeEachItem*restChildCount) / (restChildCount+1);
-                         
+                    var hasMusic = currentLocation && currentLocation.musicInfo.music
+                    if(hasMusic){
+                        var audioObj = SoundManager.list.find(e=>e.name == 'tour') 
+                        var current = audioObj.audio.currentTime * 1e3 // || 0  //g_tourAudio ? 1e3 * g_tourAudio.currentTime : 0
+                        rotTime = currentLocation.musicInfo.time - current
+                        if(restChildCount){//如果当前folder中还有剩下的item,平分一下时间
+                            rotTime = (rotTime-timeEachItem*restChildCount) / (restChildCount+1);   
+                        }  
+                    }else{
+                        rotTime = defaultRotTime
                     } 
                     rotTime = Math.max(0, rotTime)
-                    console.log("rotTime "+rotTime +" at item "+this.director.currentItem + ",musicCurrentTime:"+current) 
+                    console.log("rotTime "+rotTime +" at item "+this.director.currentItem + (hasMusic ? (",musicCurrentTime:"+current+'音乐总长:'+currentLocation.musicInfo.time) : '')) 
                 }else{
                     rotTime = currentLocation.rotTime * 1000
                     console.log("rotTime "+rotTime +" at item "+this.director.currentItem) 
@@ -24981,7 +24785,7 @@ function o(a, s, l) {
                 blur: .8,
                 movementEasing: "easeInOutQuad",
                 blendEasing: "easeInOutQuad",
-                fastForwardFactor: 3
+                fastForwardFactor: 4
             },
             show360Views: {
                 enabled: !0,

+ 40 - 229
js/main_2020_show.js

@@ -3,212 +3,6 @@
   */
  
 
-window.common = null;  
-window.MathLight = null;
-window.math = null
-window.easing = null
-window.lerp = null
-window.transitions = null
-window.browser = null
-window.momentTourBlackNewType = 0//=  number == 'TEST'//true
- 
-
-var dealMap = (map)=>{//使不resize  when   image is not power of two
-    map.wrapS = map.wrapT = THREE.ClampToEdgeWrapping;
-    map.minFilter = THREE.LinearFilter;
-    map.magFilter = THREE.LinearFilter;
-    map.generateMipmaps = true;  
-    
-}  
- 
- 
-  
-var dom = {//许钟文add
-	getOffset: function(type, element, parent) { 
-		left = (type == "left") ? element.offsetLeft : element.offsetTop;
-		if (!parent) parent = $("body")[0];
-		while (element = element.offsetParent) { 
-			if (element == parent) break;
-			left += (type == "left") ? element.offsetLeft : element.offsetTop;
-		}
-		return left;
-	}  
-};
-
-
-var getTransformSid = function(){
-    var name
-    if(player.mode == 'panorama'){
-        name = player.currentPano ? player.currentPano.id : 'outside'
-    }else{
-        name = 'outside'
-    }
-    return name
-} 
- 
-
-
- 
-var convertTool = { 
-	getPos2d : function(point, camera, dom){//获取一个三维坐标对应屏幕中的二维坐标
-		var camera = camera || player.camera;
-		var dom = dom || player.domElement;
-		var pos = point.clone().project(camera)	//比之前hotspot的计算方式写得简单  project用于3转2(求法同shader); unproject用于2转3 :new r.Vector3(e.x, e.y, -1).unproject(this.camera);
-		
-		var x,y;
-		x = (pos.x + 1) / 2 * dom.clientWidth;
-		y = (1 - (pos.y + 1) / 2) * dom.clientHeight; 
-  
-		var inSight = x <= dom.clientWidth &&  x >= 0    //是否在屏幕中   
-					&& y <= dom.clientHeight &&  y >= 0 
-	 
-	
-		return {
-			pos: new THREE.Vector2(x,y),  // 屏幕像素坐标
-			vector:  pos,   //(范围 -1 ~ 1)
-			trueSide : pos.z<1, //trueSide为false时,即使在屏幕范围内可见,也是反方向的另一个不可以被渲染的点   参见Tag.update
-			inSight : inSight	//在屏幕范围内可见
-		};
-	},
-
-	ifShelter: function(pos3d){//检测某点在视线中是否被mesh遮挡 
-		var ori = player.position
-        var dir = pos3d.clone().sub(ori).normalize()
-        var ray = new THREE.Raycaster(ori, dir) //由外向里 因为模型从内侧是可见的所以从外侧
-	
-		/* if(config.isEdit && publicObjectSet.editor.mainDesign.editing){
-			var o = ray.intersectObjects(publicObjectSet.editor.mainDesign.wallMeshes);
-		}else{ */
-			var o = ray.intersectObjects(player.model.colliders);
-		//} 
-		var len = pos3d.distanceTo(ori);
-		if (o && o.length) {
-			for(var i=0;i<o.length;i++){
-				if(o[i].distance < len){  return true;  }//有遮挡
-			} 
-		} 
-	},
-    
-    
-    /* 
-        拖拽时,获取鼠标在拖拽面上的位置(需要借助另一个intersectPlane面来计算,即和相机方向一样的面,可保证铺满屏幕)
-        但是不一定能获取到,比如鼠标射线不朝向拖拽面时,即使获取也会是一个意外的反方向的交点。
-	 */
-	getPosAtPlane : function(pos, info/* , mouse, camera */){ //pos:与intersectPlane的交点 见笔记
-		var A = pos; 
-        var player = player;      
-        var mouse = player.mouse;
-        var O = new THREE.Vector3(mouse.x, mouse.y, -1).unproject(player.camera);
-		
-		
-		if(info.y != void 0){//地面线的
-        
-            var y = info.y; 
-            
-            if(player.mode == "floorplan"/*  ||  Math.abs(O.x-pos.x)<0.0001 && Math.abs(O.z-pos.z)<0.0001) */){
-            //intersectPlane和地面平行,无交点
-                var x = pos.x, z = pos.z;
-            
-            }else{
-             
-                if(y<player.camera.position.y && O.y <= A.y /* || y>player.camera.position.y && O.y >= A.y  */)return null;  //鼠标射线向上。因为相机一定位于地面以上(地面不会抬高到相机上吧?),所以无交点。
-                if(O.y == A.y){console.log('一样??');return;}
-                if(A.y == y){console.log('一样2??');return;}
-                var r = (O.y-y)/(A.y-y);
-                var x = (r*A.x-O.x)/(r-1);
-                var z = (r*A.z-O.z)/(r-1); 
-			}
-		}else{//垂直的也有越过消失点以后反向变化的情况,但使用时影响不大
-			var N = info.normalVec;
-			var P = info.pullPos;
-			if(N.y != 0 ){console.log('N.y != 0');return;} //仅仅支持垂直于地面的的墙壁,目前都是
-			if(O.z==A.z){console.log('O.z==A.z?');return;}
-			if(N.z!=0 && N.x != 0){//直接用这个通用的也可以,支持斜线的墙
-				//console.log('N.z==0 && N.x == 0?');  
-				var c = ( N.x*(A.x-O.x) + N.y*(A.y-O.y) + N.z*(A.z-O.z));
-				if(c == 0){console.log("分母为0?? return;");return;} 
-				var t = -((N.x*O.x + N.y*O.y + N.z*O.z) - (P.x*N.x + P.y*N.y + P.z*N.z) ) / c
-				var x = t * (A.x - O.x) + O.x;
-				var y = t * (A.y - O.y) + O.y;
-				var z = t * (A.z - O.z) + O.z;
-				/*原理: 已知空间直线L:(x-a)/m=(x-b)/n=(z-c)/p和空间平面π:Ax+By+Cz+D=0;
-				求直线L与平面π的交点的坐标。
-				把直线方程改写成参数形式:设(x-a)/m=(x-b)/n=(z-c)/p=t;
-				则x=mt+a;y=nt+b;z=pt+c;代入平面π的方程得:
-				A(mt+a)+B(nt+b)+C(pt+c)+D=0
-				由此解得t=-(Aa+Bb+Cc+D)/(Am+Bn+Cp)
-				再代入参数方程即得交点的坐标(x,y,z). */
-			}else if(N.x ==0 ){ //z与pullPos相等
-				var z = P.z;
-				if(O.y == A.y){console.log('一样??');return;}
-				if(A.y == y){console.log('一样2??');return;}
-                if(A.z == z){console.log('一样3??');return;}
-				var r = (O.z-z)/(A.z-z);
-				var x = (r*A.x-O.x)/(r-1);
-				var y = (r*A.y-O.y)/(r-1);
-			}else if(N.z == 0){//x与pullPos相等
-				var x = P.x;
-				if(O.y == A.y){console.log('一样??');return;}
-				if(A.y == y){console.log('一样2??');return;}
-                if(A.x == x){console.log('一样3??');return;}
-				var r = (O.x-x)/(A.x-x);
-				var y = (r*A.y-O.y)/(r-1);
-				var z = (r*A.z-O.z)/(r-1);
-			}
-		}   
-		
-		return new THREE.Vector3(x,y,z);
-	},
-
-
-	
-	getMouseIntersect : function(camera, meshes, mouse){//获取鼠标和meshes交点
-		var raycaster = new THREE.Raycaster; 
-		camera.updateMatrixWorld(); 
-		var origin = new THREE.Vector3(mouse.x,mouse.y,-1).unproject(camera)
-		  , end = new THREE.Vector3(mouse.x,mouse.y,1).unproject(camera); 
-		var dir = end.sub(origin).normalize() 
-		raycaster.set(origin, dir);
-		var n = raycaster.intersectObjects(meshes);
-		if (0 === n.length)
-			return null;
-		return n[0];
-		
-	},
-	ifIntersectChunks : function(A,B,options={}){//获取某个线段/射线和meshes的交点 
-		var dir = B.clone().sub(A).normalize();
-		var len = options.InfinityLen ? Infinity :  A.distanceTo(B) + (options.extLen||0);
-		var ray = new THREE.Raycaster(A.clone(), dir, 0, len);
-          
-		var o = ray.intersectObjects(options.model || player.model.colliders);
-		if (o && o.length)return o;
-		  
-		if(options.throughWidth){ //允许最小宽度,防止穿过极小的缝隙导致撞墙感
-			var normal = math.getNormal({points:[{x:A.x, y:A.z},{x:B.x, y:B.z}]});//线段法线
-			normal.multiplyScalar(options.throughWidth)
-			var normalVec3 = new THREE.Vector3(normal.x, 0, normal.y);
-			
-			var A2 = A.clone().add(normalVec3)
-			ray.set(A2, dir);  
-			var o2 = ray.intersectObjects(options.model || player.model.colliders);
-			ray.set(A.clone().add(normalVec3.negate()), dir);
-			if (o2 && o2.length)return o2;
-			var o3 = ray.intersectObjects(options.model || player.model.colliders);
-			if (o3 && o3.length)return o3; 
-		} 
-		return null;
-	},
-	getPosAtSphere : function(pos3d, toPanoPos){
-		var dir = pos3d.clone().sub(toPanoPos); 
-		dir.normalize();//然后计算在球中
-		dir.multiplyScalar(Constants.skyRadius);   
-		dir.add(toPanoPos); 
-		return dir;
-	} 
-}
-
- 
-
 
 
 
@@ -4715,11 +4509,11 @@ window.Modernizr = function(n, e, t) {
                 })
             }
             ,
-            n.prototype.checkAndHandleWalkingtourInterruption = function(e) {
-                return e === u.WALK && (this.interrupt(g.NONE),
+            n.prototype.checkAndHandleWalkingtourInterruption = function(e) {//快速停止。 改:去掉判断nextWarpStyle,因为这个属性改乱了,导致点击停止按钮不执行
+                return /* e === u.WALK && ( */this.interrupt(g.NONE),
                 this.pauseWalkingSection(),
                 this.player.fastForwardActivePanoFlight(),
-                !0)
+                !0/* ) */
             }
             ,
             n.prototype.handlePlayerMove = function(e) {
@@ -4972,8 +4766,8 @@ window.Modernizr = function(n, e, t) {
                     
                         //var s = 0 === this.destinationItem || e ? u.BLACK : this.nextWarpStyle;
                         //var walk = window.DATA.black ? 'black' : 'walk';
-                     
-                        var s = this.getMomentTour(this.destinationItem)   //window.DATA.momentTour || "walk";
+                        //若是点击item,直接瞬间过渡。
+                        var s = e ? 'black' : this.getMomentTour(this.destinationItem)   //window.DATA.momentTour || "walk";
                         a1 = this.player.warpToPanoByHeroIndex.bind(this.player, this.destinationItem, v.Show, m.Slow,  s, true, i, this.actionComplete.bind(this)),
                         o = this.arrivedAtDestination.bind(this, !0)
                     
@@ -5059,8 +4853,8 @@ window.Modernizr = function(n, e, t) {
                         return;
                     this.clearWalkingSectionPaused(),
                     this.setDestinationItem(e),
-                    this.useSpecialTransition("Hilight"),
-                    this.goToDestination(),
+                    this.useSpecialTransition("Hilight")
+                    this.goToDestination(true),//add true
                     h.trackAlways("reach_highlight", {
                         reach_source: "thumb"
                     })
@@ -14638,6 +14432,10 @@ window.Modernizr = function(n, e, t) {
                     
                     
                     if(DATA.tourWalkSpeed == void 0)DATA.tourWalkSpeed = 100 
+                    
+                    if(DATA.tourRotTime == '' || DATA.tourRotTime == void 0){
+                        DATA.tourRotTime = settings.tourRotTime; //默认停留2秒
+                    }
                 }
                 
             }).fail(e=>{
@@ -17238,6 +17036,11 @@ window.Modernizr = function(n, e, t) {
                         }
                         var item = new s(l);
                         item.momentTour = info.momentTour
+                        item.dontRot = info.dontRot
+                        item.rotTime = info.rotTime
+                        
+                        
+                        
                         container.push(item) 
                         return item
                     }
@@ -18968,7 +18771,7 @@ window.Modernizr = function(n, e, t) {
             }
             ,
             n.prototype.build1 = function() {
-                this.floor = this.floor || this.model.floors.get(this.floorIndex) || this.raycastToFindFloor() || this.model.getFloorAtPoint(this.position),
+                this.floor = this.floor || this.model.floors.get(this.floorIndex) || (this.model.floors.list.length == 1 ? this.model.floors.list[0] :  this.raycastToFindFloor()) || this.model.getFloorAtPoint(this.position),
                 this.floor.addPano(this),
                 this.floorPosition = this.floorPosition || this.raycastFloorPosition(),
                 this.neighbourPanos = this.neighbourPanos || this.findNeighourPanos(),
@@ -22430,7 +22233,7 @@ window.Modernizr = function(n, e, t) {
                     e.cameraChanged = !a;
                     
                     if(e.cameraChanged){//
-                        e.cameraChanged2 = !MathLight.closeTo(this.quaternion, this.previousState.quaternion, 3) || !MathLight.closeTo(this.position, this.previousState.position, 4)  
+                        e.cameraChanged2 = !MathLight.closeTo(this.quaternion, this.previousState.quaternion, 3) || !MathLight.closeTo(this.position, this.previousState.position, 4)  || !this.camera.projectionMatrix.equals(this.previousState.projectionMatrix)
                     }else e.cameraChanged2 = false 
                     
                     
@@ -23112,8 +22915,8 @@ window.Modernizr = function(n, e, t) {
             
             
             n.prototype.fastForwardActivePanoFlight = function(e) {
-                e = e || f.transition.fastForwardFactor / 10 * 4 + 1,
-                y.adjustSpeed(V.FlyToPano, e),
+                e = e || f.transition.fastForwardFactor / 10 * 4 + 1 
+                y.adjustSpeed(V.FlyToPano, e) 
                 y.adjustSpeed(V.LookTransition, e)
             }
             ,
@@ -23728,25 +23531,31 @@ window.Modernizr = function(n, e, t) {
                 this.history.invalidate();
                 this.path.discardSlow();
 				//xzw:  
-                
-                var timeEachItem = 2e3 / (DATA.tourWalkSpeed + DATA.tourBlackSpeed) * 200 //预估时间假设每个item飞的时间
+                var defaultRotTime = DATA.tourRotTime * 1000
+                var timeEachItem = 2e3 / (DATA.tourWalkSpeed + DATA.tourBlackSpeed) * 200 //预估时间假设每个item飞的时间(如果距离远就少了)
+                 
                 var currentLocation = this.model.heroLocations[this.director.currentItem[0]] 
                 var rotTime
                 if(currentLocation.rotTime == void 0 || currentLocation.rotTime == ''){
                     var restChildCount = currentLocation.heroLocations ? (currentLocation.heroLocations.length-this.director.currentItem[1]-1) : 0
-                    var audioObj = SoundManager.list.find(e=>e.name == 'tour')
-                    var current = audioObj.audio.currentTime * 1e3 // || 0  //g_tourAudio ? 1e3 * g_tourAudio.currentTime : 0
-                    rotTime = currentLocation && currentLocation.musicInfo.music ? currentLocation.musicInfo.time - current : timeEachItem;  
-                    
-                    if(restChildCount){//如果当前folder中还有剩下的item,平分一下时间
-                        var rotTime = (rotTime-timeEachItem*restChildCount) / (restChildCount+1);
+                    var hasMusic = currentLocation && currentLocation.musicInfo.music
+                    if(hasMusic){
+                        var audioObj = SoundManager.list.find(e=>e.name == 'tour') 
+                        var current = audioObj.audio.currentTime * 1e3 // || 0  //g_tourAudio ? 1e3 * g_tourAudio.currentTime : 0
+                        rotTime = currentLocation.musicInfo.time - current
+                        if(restChildCount){//如果当前folder中还有剩下的item,平分一下时间
+                            rotTime = (rotTime-timeEachItem*restChildCount) / (restChildCount+1);   
+                        }  
+                    }else{
+                        rotTime = defaultRotTime
                     } 
                     rotTime = Math.max(0, rotTime)
-                    console.log("rotTime "+rotTime +" at item "+this.director.currentItem + ",musicCurrentTime:"+current) 
+                    Log("rotTime "+rotTime +" at item "+this.director.currentItem + (hasMusic ? (",musicCurrentTime:"+current+'音乐总长:'+currentLocation.musicInfo.time) : ''),"#E8E") 
                 }else{
                     rotTime = currentLocation.rotTime * 1000
-                    console.log("rotTime "+rotTime +" at item "+this.director.currentItem) 
+                    Log("rotTime "+rotTime +" at item "+this.director.currentItem,"#E8E") 
                 }
+                 
 
                 this.path.waitNextStep(e, function() {
                     t && t()
@@ -23757,7 +23566,9 @@ window.Modernizr = function(n, e, t) {
                 this.interruptAndFastForward(null, 0)
             }
             ,
-            n.prototype.interruptAndFastForward = function(e, t) {
+            n.prototype.interruptAndFastForward = function(e, t) { 
+                //Log('interruptAndFastForward' , '#f00')
+                
                 this.isWarping() && this.emit(w.WarpInterrupted, this.path.activeTransType, e, t),
                 this.flying && this.emit(w.FlyingInterrupted),
                 this.path.interruptAndFastForward(e, t)
@@ -26273,7 +26084,7 @@ window.Modernizr = function(n, e, t) {
                 blur: 0.8,
                 movementEasing: "easeInOutQuad",
                 blendEasing: "easeInOutQuad",
-                fastForwardFactor: 3//r.valueFromHash("mfis", 3)
+                fastForwardFactor: 4,//r.valueFromHash("mfis", 3) //快速停止导览的速度,原先是3
             },
             show360Views: {
                 enabled: !0,

+ 248 - 1
js/manage.js

@@ -80,7 +80,7 @@ var settings = {
     teleportTime:  1500,//瞬间过渡的时间 
     /* flytimeDistanceMultiplier:150, 
     flyTime:750,  */
-    
+    tourRotTime:2,  //默认停留2秒
     //dontExamHot:true  
     transparentBg: false,
     bgImg:  null 
@@ -90,6 +90,253 @@ if(window.number == '725'||window.number == '724'){
 }
 
 
+//共用函数:
+
+
+window.common = null;  
+window.MathLight = null;
+window.math = null
+window.easing = null
+window.lerp = null
+window.transitions = null
+window.browser = null
+window.momentTourBlackNewType = 0//=  number == 'TEST'//true
+ 
+
+
+
+
+
+
+
+
+
+var dealMap = (map)=>{//使不resize  when   image is not power of two
+    map.wrapS = map.wrapT = THREE.ClampToEdgeWrapping;
+    map.minFilter = THREE.LinearFilter;
+    map.magFilter = THREE.LinearFilter;
+    map.generateMipmaps = true;  
+    
+}  
+ 
+ 
+  
+var dom = { 
+	getOffset: function(type, element, parent) { 
+		left = (type == "left") ? element.offsetLeft : element.offsetTop;
+		if (!parent) parent = $("body")[0];
+		while (element = element.offsetParent) { 
+			if (element == parent) break;
+			left += (type == "left") ? element.offsetLeft : element.offsetTop;
+		}
+		return left;
+	}  
+};
+
+
+var getTransformSid = function(){
+    var name
+    if(player.mode == 'panorama'){
+        name = player.currentPano ? player.currentPano.id : 'outside'
+    }else{
+        name = 'outside'
+    }
+    return name
+} 
+ 
+
+
+ 
+var convertTool = { 
+	getPos2d : function(point, camera, dom){//获取一个三维坐标对应屏幕中的二维坐标
+		var camera = camera || player.camera;
+		var dom = dom || player.domElement;
+		var pos = point.clone().project(camera)	//比之前hotspot的计算方式写得简单  project用于3转2(求法同shader); unproject用于2转3 :new r.Vector3(e.x, e.y, -1).unproject(this.camera);
+		
+		var x,y;
+		x = (pos.x + 1) / 2 * dom.clientWidth;
+		y = (1 - (pos.y + 1) / 2) * dom.clientHeight; 
+  
+		var inSight = x <= dom.clientWidth &&  x >= 0    //是否在屏幕中   
+					&& y <= dom.clientHeight &&  y >= 0 
+	 
+	
+		return {
+			pos: new THREE.Vector2(x,y),  // 屏幕像素坐标
+			vector:  pos,   //(范围 -1 ~ 1)
+			trueSide : pos.z<1, //trueSide为false时,即使在屏幕范围内可见,也是反方向的另一个不可以被渲染的点   参见Tag.update
+			inSight : inSight	//在屏幕范围内可见
+		};
+	},
+
+	ifShelter: function(pos3d){//检测某点在视线中是否被mesh遮挡 
+		var ori = player.position
+        var dir = pos3d.clone().sub(ori).normalize()
+        var ray = new THREE.Raycaster(ori, dir) //由外向里 因为模型从内侧是可见的所以从外侧
+	
+		/* if(config.isEdit && publicObjectSet.editor.mainDesign.editing){
+			var o = ray.intersectObjects(publicObjectSet.editor.mainDesign.wallMeshes);
+		}else{ */
+			var o = ray.intersectObjects(player.model.colliders);
+		//} 
+		var len = pos3d.distanceTo(ori);
+		if (o && o.length) {
+			for(var i=0;i<o.length;i++){
+				if(o[i].distance < len){  return true;  }//有遮挡
+			} 
+		} 
+	},
+    
+    
+    /* 
+        拖拽时,获取鼠标在拖拽面上的位置(需要借助另一个intersectPlane面来计算,即和相机方向一样的面,可保证铺满屏幕)
+        但是不一定能获取到,比如鼠标射线不朝向拖拽面时,即使获取也会是一个意外的反方向的交点。
+	 */
+	getPosAtPlane : function(pos, info/* , mouse, camera */){ //pos:与intersectPlane的交点 见笔记
+		var A = pos; 
+        var player = player;      
+        var mouse = player.mouse;
+        var O = new THREE.Vector3(mouse.x, mouse.y, -1).unproject(player.camera);
+		
+		
+		if(info.y != void 0){//地面线的
+        
+            var y = info.y; 
+            
+            if(player.mode == "floorplan"/*  ||  Math.abs(O.x-pos.x)<0.0001 && Math.abs(O.z-pos.z)<0.0001) */){
+            //intersectPlane和地面平行,无交点
+                var x = pos.x, z = pos.z;
+            
+            }else{
+             
+                if(y<player.camera.position.y && O.y <= A.y /* || y>player.camera.position.y && O.y >= A.y  */)return null;  //鼠标射线向上。因为相机一定位于地面以上(地面不会抬高到相机上吧?),所以无交点。
+                if(O.y == A.y){console.log('一样??');return;}
+                if(A.y == y){console.log('一样2??');return;}
+                var r = (O.y-y)/(A.y-y);
+                var x = (r*A.x-O.x)/(r-1);
+                var z = (r*A.z-O.z)/(r-1); 
+			}
+		}else{//垂直的也有越过消失点以后反向变化的情况,但使用时影响不大
+			var N = info.normalVec;
+			var P = info.pullPos;
+			if(N.y != 0 ){console.log('N.y != 0');return;} //仅仅支持垂直于地面的的墙壁,目前都是
+			if(O.z==A.z){console.log('O.z==A.z?');return;}
+			if(N.z!=0 && N.x != 0){//直接用这个通用的也可以,支持斜线的墙
+				//console.log('N.z==0 && N.x == 0?');  
+				var c = ( N.x*(A.x-O.x) + N.y*(A.y-O.y) + N.z*(A.z-O.z));
+				if(c == 0){console.log("分母为0?? return;");return;} 
+				var t = -((N.x*O.x + N.y*O.y + N.z*O.z) - (P.x*N.x + P.y*N.y + P.z*N.z) ) / c
+				var x = t * (A.x - O.x) + O.x;
+				var y = t * (A.y - O.y) + O.y;
+				var z = t * (A.z - O.z) + O.z;
+				/*原理: 已知空间直线L:(x-a)/m=(x-b)/n=(z-c)/p和空间平面π:Ax+By+Cz+D=0;
+				求直线L与平面π的交点的坐标。
+				把直线方程改写成参数形式:设(x-a)/m=(x-b)/n=(z-c)/p=t;
+				则x=mt+a;y=nt+b;z=pt+c;代入平面π的方程得:
+				A(mt+a)+B(nt+b)+C(pt+c)+D=0
+				由此解得t=-(Aa+Bb+Cc+D)/(Am+Bn+Cp)
+				再代入参数方程即得交点的坐标(x,y,z). */
+			}else if(N.x ==0 ){ //z与pullPos相等
+				var z = P.z;
+				if(O.y == A.y){console.log('一样??');return;}
+				if(A.y == y){console.log('一样2??');return;}
+                if(A.z == z){console.log('一样3??');return;}
+				var r = (O.z-z)/(A.z-z);
+				var x = (r*A.x-O.x)/(r-1);
+				var y = (r*A.y-O.y)/(r-1);
+			}else if(N.z == 0){//x与pullPos相等
+				var x = P.x;
+				if(O.y == A.y){console.log('一样??');return;}
+				if(A.y == y){console.log('一样2??');return;}
+                if(A.x == x){console.log('一样3??');return;}
+				var r = (O.x-x)/(A.x-x);
+				var y = (r*A.y-O.y)/(r-1);
+				var z = (r*A.z-O.z)/(r-1);
+			}
+		}   
+		
+		return new THREE.Vector3(x,y,z);
+	},
+
+
+	
+	getMouseIntersect : function(camera, meshes, mouse){//获取鼠标和meshes交点
+		var raycaster = new THREE.Raycaster; 
+		camera.updateMatrixWorld(); 
+		var origin = new THREE.Vector3(mouse.x,mouse.y,-1).unproject(camera)
+		  , end = new THREE.Vector3(mouse.x,mouse.y,1).unproject(camera); 
+		var dir = end.sub(origin).normalize() 
+		raycaster.set(origin, dir);
+		var n = raycaster.intersectObjects(meshes);
+		if (0 === n.length)
+			return null;
+		return n[0];
+		
+	},
+	ifIntersectChunks : function(A,B,options={}){//获取某个线段/射线和meshes的交点 
+		var dir = B.clone().sub(A).normalize();
+		var len = options.InfinityLen ? Infinity :  A.distanceTo(B) + (options.extLen||0);
+		var ray = new THREE.Raycaster(A.clone(), dir, 0, len);
+          
+		var o = ray.intersectObjects(options.model || player.model.colliders);
+		if (o && o.length)return o;
+		  
+		if(options.throughWidth){ //允许最小宽度,防止穿过极小的缝隙导致撞墙感
+			var normal = math.getNormal({points:[{x:A.x, y:A.z},{x:B.x, y:B.z}]});//线段法线
+			normal.multiplyScalar(options.throughWidth)
+			var normalVec3 = new THREE.Vector3(normal.x, 0, normal.y);
+			
+			var A2 = A.clone().add(normalVec3)
+			ray.set(A2, dir);  
+			var o2 = ray.intersectObjects(options.model || player.model.colliders);
+			ray.set(A.clone().add(normalVec3.negate()), dir);
+			if (o2 && o2.length)return o2;
+			var o3 = ray.intersectObjects(options.model || player.model.colliders);
+			if (o3 && o3.length)return o3; 
+		} 
+		return null;
+	},
+    
+	getPosAtSphere : function(pos3d, toPanoPos){
+		var dir = pos3d.clone().sub(toPanoPos); 
+		dir.normalize();//然后计算在球中
+		dir.multiplyScalar(Constants.skyRadius);   
+		dir.add(toPanoPos); 
+		return dir;
+	} ,
+    
+    getScaleForConstantSize : function(op={}){ //获得规定二维大小的mesh的scale值。可以避免因camera的projection造成的mesh视觉大小改变。  来源:tag.updateDisc
+        var w;  
+        var i = new THREE.Vector3, o = new THREE.Vector3, l = new THREE.Vector3, c = new THREE.Vector3, h = new THREE.Vector3
+         
+        if(op.width2d) w = op.width2d //如果恒定二维宽度
+        else{//否则考虑上距离,加一丢丢近大远小的效果
+            var currentDis, nearBound, farBound
+            if(op.camera.type == "OrthographicCamera"){
+                currentDis = (op.camera.right - op.camera.left) / op.camera.zoom
+            }else{
+                currentDis = op.position.distanceTo(op.camera.position);
+            } 
+            w = op.maxSize - ( op.maxSize -  op.minSize) * THREE.Math.smoothstep(currentDis,  op.nearBound,  op.farBound);
+            //maxSize : mesh要表现的最大像素宽度;   nearBound: 最近距离,若比nearBound近,则使用maxSize
+        }
+        i.copy(op.position).project(op.camera),  //tag中心在屏幕上的二维坐标
+        o.set(op.resolution.x / 2, op.resolution.y / 2, 1).multiply(i), //转化成px   -w/2 到 w/2的范围
+        l.set(w / 2, 0, 0).add(o),  //加上tag宽度的一半
+        c.set(2 / op.resolution.x, 2 / op.resolution.y, 1).multiply(l), //再转回  -1 到 1的范围
+        h.copy(c).unproject(op.camera);//再转成三维坐标,求得tag边缘的位置
+        var g = h.distanceTo(op.position)//就能得到tag的三维半径
+    
+        return g  //可能NAN  当相机和position重叠时
+         
+    } 
+    
+    
+    
+}
+
+ 
+