Pārlūkot izejas kodu

fix: cabinet改宽到1米多。searchPair时直接计算score,提前过滤不合格的组合,防止大场景卡住

xzw 1 gadu atpakaļ
vecāks
revīzija
1efb02ba48
1 mainītis faili ar 287 papildinājumiem un 204 dzēšanām
  1. 287 204
      service/PanoBoxFrame.js

+ 287 - 204
service/PanoBoxFrame.js

@@ -15,24 +15,26 @@ const convertTool = {
 }
 
 //----------------------复制以下内容--------------------------------- 
-
- 
+  
 let player,
     skyBoxTight,
     meshGroup,
     modelBound = new THREE.Box3(),
     ray = new THREE.Raycaster(),
-    groundPlane = new THREE.Plane()
-let groundY, safeBound, boundConfirmed //安全区域应该在扣除每种类型柜子大概的长宽的一半
-let hue = 0,
-    startTime
+    groundPlane = new THREE.Plane(),
+    groundY,
+    safeBound,
+    boundConfirmed, //安全区域应该在扣除每种类型柜子大概的长宽的一半
+    hue = 0,
+    startTime,
+    isLaser,
+    boxesSolid = []
+
 const MinBoxInitialScore = 0.68 //找不到匹配时,若box分数低于该值,不createSinglePano
-let boxesSolid = []
-  
 
 let standards = {
     cabinet: {
-        widthNormal: { min: 0.55, max: 0.65 }, //widthNormal是不计宽还是厚度的平均宽度  //个别场景如S9yepREK8Jl 宽0.8米
+        widthNormal: { min: 0.55, max: 1.05 /* max: 0.65  */ }, //widthNormal是不计宽还是厚度的平均宽度  //个别场景如S9yepREK8Jl 宽0.8米
         height: { min: 0.3, max: 2.5, standard: 2 },
         closeRatio: 0.7, //数值越小越容易findRest。一般在墙上的位置不准要设置大些,扎堆放置的设置小些
     },
@@ -157,6 +159,7 @@ for(let i in typeNames){
  */
 
 let addLine = (origin, dir, len, color) => {
+    return
     if (version != 'vision') return
     var line1 = LineDraw.createLine([origin, origin.clone().add(dir.clone().multiplyScalar(len || 1))], { color })
     //console.log(origin.toArray(), dir.toArray())
@@ -233,8 +236,8 @@ class Box {
     constructor(info) {
         //preDealBox(info)
         this.setFromInfo(info)
-        this.name = this.boxType + '-' + this.name
-        if (version == 'vision' && boundConfirmed) this.draw()
+        this.buildFromData || (this.name = this.boxType + '-' + this.name)
+        if (version == 'vision' && (this.buildFromData || boundConfirmed)) this.draw()
 
         boxesSolid.push(this)
     }
@@ -251,16 +254,9 @@ class Box {
             info.size.y = h
         } */
 
-        this.position = getBoxFinalPos(this)
+        this.position = this.buildFromData ? this.center : getBoxFinalPos(this)
         let bound = new THREE.Box3().setFromCenterAndSize(this.position, this.size)
         this.bound = bound
-        
-        
-        
-        
-        
-        
-        
     }
 
     draw() {
@@ -277,6 +273,12 @@ class Box {
 
         this.label = addLabel(this.position, /* exStr ? [this.name, exStr] :  */ this.score ? [this.name, this.score.toFixed(1)] : this.name, { bgcolor: color })
 
+        /* //color = new THREE.Color('#fff')   
+        let box = new THREE.Mesh(new THREE.BoxBufferGeometry(), new THREE.MeshBasicMaterial({color, opacity:0.5, transparent:true}))
+        box.position.copy(this.position)
+        box.scale.copy(this.size)
+        meshGroup.add(box) */
+
         meshGroup.add(this.boxHelper)
     }
 
@@ -295,31 +297,34 @@ class Box {
         traverse(this, fun)
     }
 
+    getDirection() {
+        //获得正面朝向。  需要全部box都创建完再调用
 
-    getDirection(){//获得正面朝向。  需要全部box都创建完再调用
-           
         let xProp = this.xProp
-        let dir 
+        let dir
         //哪边pano多朝哪边
-        
-        
-        if(this.boxType == 'cabinet' && this.name.includes('row')){
-            if(this.infos.box.length>1){
-                let k = this.infos.reduce((w,c)=>{return w+c.k},0)
-                xProp = k>1 ? 'width' : 'thick' 
-            }else{ //直接使用别的多box的row的方向 ,大多数都相同(会有例外,无所谓了)
-                let rows = boxesSolid.filter(e=>e.boxType == 'cabinet' && e.name.includes('row') && e.dirQua)
-                rows.sort((a,b)=>b.infos.box.length - a.infos.box.length) 
-                let box = rows[0] 
-                if(box){
-                    return  this.dirQua = box.dirQua 
-                } 
+
+        if (this.boxType == 'cabinet' && this.name.includes('row')) {
+            if (this.infos.box.length > 1) {
+                let k = this.infos.reduce((w, c) => {
+                    return w + c.k
+                }, 0)
+                xProp = k > 1 ? 'width' : 'thick'
+            } else {
+                //直接使用别的多box的row的方向 ,大多数都相同(会有例外,无所谓了)
+                let rows = boxesSolid.filter(e => e.boxType == 'cabinet' && e.name.includes('row') && e.dirQua)
+                rows.sort((a, b) => b.infos.box.length - a.infos.box.length)
+                let box = rows[0]
+                if (box) {
+                    return (this.dirQua = box.dirQua)
+                }
             }
         }
-        
-        if(!xProp){//根据房间的长宽 散落的cabinet。   fire monitor
-        
-            let {xWidthPossible, yWidthPossible} = getBoxDirProp(this,true)
+
+        if (!xProp) {
+            //根据房间的长宽 散落的cabinet。   fire monitor
+
+            let { xWidthPossible, yWidthPossible } = getBoxDirProp(this, true)
             xProp = this.xProp
             /* if(Math.abs(xWidthPossible - yWidthPossible) < 0.3){
                 let size = new THREE.Vector3()
@@ -331,41 +336,39 @@ class Box {
                     xProp = 'width'
                 }
             } */
-            
-            
         }
-        
-        if(xProp){
-            
-            if(!this.panosDir)  getPanosDir(this)
-            
-            if(xProp == 'width'){
-                 
-                if (Math.abs(this.panosDir['z+']) < Math.abs(this.panosDir['z-'])) {//朝-z//也就是新坐标系的y
-                    //this.dirQua='下' 
-                    dir = new THREE.Vector3(0,1,0)
-                }else{//朝+z
-                    //this.dirQua='上' 
-                    dir = new THREE.Vector3(0,-1,0)
+
+        if (xProp) {
+            if (!this.panosDir) getPanosDir(this)
+
+            if (xProp == 'width') {
+                if (Math.abs(this.panosDir['z+']) < Math.abs(this.panosDir['z-'])) {
+                    //朝-z//也就是新坐标系的y
+                    //this.dirQua='下'
+                    dir = new THREE.Vector3(0, 1, 0)
+                } else {
+                    //朝+z
+                    //this.dirQua='上'
+                    dir = new THREE.Vector3(0, -1, 0)
                 }
-            }else{
-                if (Math.abs(this.panosDir['x+']) < Math.abs(this.panosDir['x-'])) {//朝-x
-                    //this.dirQua='右' 
-                    dir = new THREE.Vector3(-1,0,0)
-                }else{//朝+x
-                     //this.dirQua='左' 
-                     dir = new THREE.Vector3(1,0,0)
+            } else {
+                if (Math.abs(this.panosDir['x+']) < Math.abs(this.panosDir['x-'])) {
+                    //朝-x
+                    //this.dirQua='右'
+                    dir = new THREE.Vector3(-1, 0, 0)
+                } else {
+                    //朝+x
+                    //this.dirQua='左'
+                    dir = new THREE.Vector3(1, 0, 0)
                 }
             }
-        } 
+        }
         //addLabel(this.position, this.dirQua)
-          
-            
-        this.dirQua = convertTool.getQuaByAim(dir, new THREE.Vector3, new THREE.Vector3(0,1,0)) 
-        return   this.dirQua 
-        
-        
-      /*飞到俯视图查看(不旋转视图,x朝右,z朝下)。以下四个qua是四个墙壁每个墙壁上的dirQua。 
+
+        this.dirQua = convertTool.getQuaByAim(dir, new THREE.Vector3(), new THREE.Vector3(0, 1, 0))
+        return this.dirQua
+
+        /*飞到俯视图查看(不旋转视图,x朝右,z朝下)。以下四个qua是四个墙壁每个墙壁上的dirQua。 
       
                                      _x: 0, _y: -0, _z: 1, _w: 0 
     
@@ -376,10 +379,10 @@ class Box {
                                     x: 0, _y: 0, _z: 0, _w: 1
                              
      */
-        
     }
 
-    toJson() {//转出的坐标系是z朝上的
+    toJson() {
+        //转出的坐标系是z朝上的
         let category = typeNames[this.boxType]
         if (category instanceof Array) {
             let scoreMap = new Map()
@@ -400,7 +403,7 @@ class Box {
             })
             category = category[0] //最高分
         }
-         
+
         this.getDirection()
 
         let json = {
@@ -408,7 +411,7 @@ class Box {
             category,
             type: this.boxType,
             sid: this.name,
-            quaternion:this.dirQua.toArray()
+            quaternion: this.dirQua.toArray(),
         }
         return json
     }
@@ -506,17 +509,24 @@ let getOtherPos = box => {
     }
 }
 
-let getUVs = box => {
+let getUVs = (box,imageWidth,imageHeight) => {
     if (box.bbox2) return
     let uvs = []
-    box.bbox2 = box.bbox.map((e, i) => {
-        return i % 2 == 0 ? e / 4096 /*   + 0.25 */ : e / 2048
+    if(!imageWidth){
+        imageWidth = boxFrame.datas[box.pano.id].imageWidth
+        imageHeight = boxFrame.datas[box.pano.id].imageHeight
+    } 
+    if(imageWidth != imageWidth || imageHeight != imageHeight){
+        console.log(imageWidth,imageHeight)
+    }
+    box.bbox2 = box.bbox.map((e, i) => {    //(x1,y1,x2,y2)
+        return i % 2 == 0 ? e / imageWidth /*   + 0.25 */ : e / imageHeight
     })
 }
 
-let getBoxBase = box => {
+let getBoxBase = (box,imageWidth,imageHeight) => {
     getBoxType(box)
-    getUVs(box)
+    getUVs(box,imageWidth,imageHeight)
     getCenterDir(box)
     getOtherPos(box)
 }
@@ -702,8 +712,8 @@ let getBoxPos = info => {
     )
 }
 
-let isType = (box, type) => {
-    return typeNames[type] instanceof Array ? typeNames[type].includes(box.category) : typeNames[type] == box.category
+let isType = (category, type) => { 
+    return type == category || typeNames[type] instanceof Array ? typeNames[type].includes(category) : typeNames[type] == category
 }
 
 let getBoxType = info => {
@@ -717,10 +727,17 @@ let getBoxType = info => {
             console.log(1)
         }
         for (let i in typeNames) {
-            if (typeNames[i] instanceof Array ? typeNames[i].includes(category) : typeNames[i] == category) {
+            /* if (i == category || typeNames[i] instanceof Array ? typeNames[i].includes(category) : typeNames[i] == category) {
                 type = i
                 break //type = typeNamesReverse[type]
+            } */
+            
+            
+            if (isType(category,i)){
+                type = i
+                break
             }
+            
         }
         /* if(type == 'ac' || type == 'dc'){
             type = 'electric'  //合并
@@ -763,7 +780,7 @@ let getBoxType = info => {
         info.type = type
     }
 } */
-let getPanosDir = (info, center) =>{
+let getPanosDir = (info, center) => {
     center = center || getBoxPos(info)
     let dirs = { 'x+': 0, 'x-': 0, 'z+': 0, 'z-': 0, got: false }
     let getDirs = () => {
@@ -785,15 +802,13 @@ let getPanosDir = (info, center) =>{
         dirs.got = true
     }
     getDirs()
-    if(info.panosDir){
+    if (info.panosDir) {
         console.error('already has dir')
     }
-    
+
     info.panosDir = dirs
-    
-        
+
     return dirs
-    
 }
 let getBoxDirProp = (info, force) => {
     //仅适用于方形单个房间房间,不可以是多边形、两个房间
@@ -804,7 +819,7 @@ let getBoxDirProp = (info, force) => {
     }
 
     //if (info.boxType == 'battery' || info.boxType == 'air-hanging' || info.boxType == 'air' || info.category == 'battery' || info.category == 'air') {
-    if (standards[info.boxType].atWall && standards[info.boxType].thick || force ) {
+    if ((standards[info.boxType].atWall && standards[info.boxType].thick) || force) {
         //根据比例判断
         /* let r1 = Math.abs((center.x - skyBoxTight.position.x) / (center.z - skyBoxTight.position.z))
         let r2 = player.model.size.x / player.model.size.z 
@@ -823,9 +838,9 @@ let getBoxDirProp = (info, force) => {
         let bound = safeBound
         let minXDiff = Math.min(center.x - bound.min.x, bound.max.x - center.x)
         let minYDiff = Math.min(center.z - bound.min.z, bound.max.z - center.z)
-        
+
         let dirs = getPanosDir(info, center)
-        
+
         let noX = dirs['x+'] == 0 || dirs['x-'] == 0,
             noZ = dirs['z+'] == 0 || dirs['z-'] == 0
 
@@ -840,7 +855,6 @@ let getBoxDirProp = (info, force) => {
         } else if (dirs['z-'] == 0 && dirs['z+'] != 0) {
             minYDiff = center.z - bound.min.z
         }
-        
 
         let xWidthPossible = noZ ? 1 : 0,
             yWidthPossible = noX ? 1 : 0
@@ -854,8 +868,9 @@ let getBoxDirProp = (info, force) => {
             }
         }
 
-        if (!xProp) { 
-            if(!force){//force的话是fire等无方向的类型
+        if (!xProp) {
+            if (!force) {
+                //force的话是fire等无方向的类型
                 if (info.category) {
                     //是box
                     info.pose || (info.pose = getBoxPoseByPos(info, center))
@@ -872,7 +887,6 @@ let getBoxDirProp = (info, force) => {
                         }
                     })
                 }
-
             }
             /* if(noX!=noZ){
                 if(noX)xWidthPossible
@@ -886,12 +900,8 @@ let getBoxDirProp = (info, force) => {
         }
 
         xProp && ((info.xProp = xProp), (info.yProp = yProp))
-        
-         
-        return {xWidthPossible, yWidthPossible}
-         
-           
-        
+
+        return { xWidthPossible, yWidthPossible }
     }
 }
 
@@ -999,7 +1009,7 @@ let getBoxPoseByPos = (box, centerPos, addDis = 0) => {
 
     //判断方向
     let o = { box, projectWidth, camTangent, maxProjectWidth, minProjectWidth, dis, maxX, maxY, minX, minY }
-    if (config.atWall > 0 /* isType(box,battery) || isType(box,air)   */) {
+    if (config.atWall > 0 /* isType(box.category,battery) || isType(box.category,air)   */) {
         //为了获取朝向
         o.xWidthPossible = -Math.abs(projectWidth - camTangent.x * maxWidth - camTangent.y * minWidth)
         o.yWidthPossible = -Math.abs(projectWidth - camTangent.x * minWidth - camTangent.y * maxWidth)
@@ -1253,18 +1263,52 @@ let getLeftRight = boxArr => {
     }
 }
 
-let searchPair = (beginItem, group0_, group1_, parentPairs, resultPairs) => {
-    let pair = [] //只能是来自group0的
-    if (parentPairs) {
-        //元结点裂变出多个,来装新的pair
-        let i = resultPairs.indexOf(parentPairs)
-        resultPairs.splice(i, 1)
-    }
 
+window.searchCount1 = 0, window.escapeCount1 = 0
+
+let searchPair = (beginItem, group0_, group1_, parentPairs, resultPairs, evaluateFun, minScore) => {//配对结果个数为n!,其中n是每组的元素个数。注意当n=10时,已经有40320个,非常恐怖。
+    let pair = [] , parentExit = !!parentPairs
+    let removeParent = ()=>{ //元结点裂变出多个,来装新的pair
+        if(parentExit){
+            let i = resultPairs.indexOf(parentPairs)
+            resultPairs.splice(i, 1)
+            parentExit = false
+        }
+        
+    } 
+    if (!parentPairs) {//首次
+        if(group0_.length == 0 || group1_.length == 0 )return 
+        //保证第一个的个数<=第二个,否则第一组多出来的永远匹配不上
+        if (group0_.length > group1_.length) {
+            let t = group0_
+            group0_ = group1_
+            group1_ = t
+        }  
+        beginItem = group0_[0]  
+        let complex = Object.keys(boxFrame.datas).length 
+        if(complex < 10) evaluateFun = null 
+        else  minScore = math.linearClamp(complex, 10, 80,  -4000, -500) 
+         
+        //console.log('searchPair length',group0_.length,group1_.length)
+        
+    }
+    searchCount1 ++
     for (let j = 0; j < group1_.length; j++) {
         pair = [beginItem, group1_[j]]
+        //if(pair[0].sid == 'void' || pair[1].sid == 'void')continue
+        let evaluate
+        if(evaluateFun/*  && !(pair[0].sid == 'void' || pair[1].sid == 'void') */){
+            evaluate = evaluateFun(pair[0],pair[1]); 
+            if(evaluate == void 0 || evaluate.score<=minScore){
+                //console.log('因为评估出匹配可能性低所以跳过',pair[0],pair[1],evaluate)
+                escapeCount1 ++
+                continue
+            }
+        } 
+         
         let newPairs //用来存放该组pair
         if (parentPairs) {
+            removeParent()
             newPairs = parentPairs.slice(0) //复制
             newPairs.push(pair)
         } else {
@@ -1280,10 +1324,21 @@ let searchPair = (beginItem, group0_, group1_, parentPairs, resultPairs) => {
         newGroup1.splice(index, 1)
 
         if (newGroup0.length > 0 && newGroup1.length > 0) {
-            searchPair(newGroup0[0], newGroup0, newGroup1, newPairs, resultPairs)
+            searchPair(newGroup0[0], newGroup0, newGroup1, newPairs, resultPairs, evaluateFun, minScore )
         }
     }
 }
+//如果第一个元素就和后面所有的都不匹配,就直接返回了怎么办?
+
+
+
+
+
+ 
+
+
+
+
 
 export default class PanoBoxFrame extends THREE.Group {
     constructor(player_, ifAnalyze, dataList) {
@@ -1291,6 +1346,7 @@ export default class PanoBoxFrame extends THREE.Group {
         this.clear()
         player = player_
         player.model.add(this)
+
         this.ifAnalyze = ifAnalyze
         this.wireframes = new THREE.Object3D()
         this.wireframes.name = 'wireframes'
@@ -1303,14 +1359,18 @@ export default class PanoBoxFrame extends THREE.Group {
         this.add(meshGroup)
 
         this.compute(dataList)
-    } 
+    }
 
     async compute(dataList) {
         startTime = Date.now()
+
         this.datas = {}
         this.datasMixed = {}
         this.boxesSolid = boxesSolid
 
+        let metadata = await player.$app.resource.metadata()
+        isLaser = metadata.sceneFrom == 'laser'
+
         let compu = 0
         let beginCompute = () => {
             //获取匹配分数
@@ -2048,24 +2108,14 @@ export default class PanoBoxFrame extends THREE.Group {
                             if (searchType == 'second') rowBigBoxes_1 = rowBigBoxes_1.filter(e => !matchGroups.some(u => u.includes(e)))
 
                             let pano1 = groups[j][0].pano
-
-                            let resultPairs = []
-                            let bigBoxes_0, bigBoxes_1
-                            if (rowBigBoxes_0.length < rowBigBoxes_1.length) {
-                                bigBoxes_0 = rowBigBoxes_1.slice()
-                                bigBoxes_1 = rowBigBoxes_0.slice()
-                            } else {
-                                bigBoxes_0 = rowBigBoxes_0.slice()
-                                bigBoxes_1 = rowBigBoxes_1.slice()
-                            }
-
-                            while (bigBoxes_1.length < bigBoxes_0.length) {
-                                bigBoxes_1.push({ sid: 'void' }) //为了使排列正确,补个空,使左右两边个数相等,过后和void匹配的不会计算box
-                            }
-
-                            if (!bigBoxes_0[0]) continue
-
-                            searchPair(bigBoxes_0[0], bigBoxes_0, bigBoxes_1, null, resultPairs)
+if(pano0.id == 54 && pano1.id == 56){
+    console.log(2)
+}
+                            let resultPairs = [] 
+                            let evaluateFun = (row0, row1)=>{
+                                return getRowMatchInfo(row0, row1, ignoreCountMatch)
+                            } 
+                            searchPair(null/* bigBoxes_0[0] */, rowBigBoxes_0.slice(), rowBigBoxes_1.slice(), null, resultPairs,  evaluateFun)
 
                             resultPairs = resultPairs.map(pairs => {
                                 let infos = pairs.map(pair => (pair.some(e => e.sid == 'void') ? null : getRowMatchInfo(pair[0], pair[1], ignoreCountMatch)))
@@ -2088,7 +2138,7 @@ export default class PanoBoxFrame extends THREE.Group {
                                 console.log(111)
                             } */
 
-                            resultPairs[0].pairs.forEach((pair, i) => {
+                            resultPairs[0] && resultPairs[0].pairs.forEach((pair, i) => {
                                 let info = resultPairs[0].infos[i]
                                 if (info && info.score > minScore) {
                                     allRelations.push(info)
@@ -2523,7 +2573,7 @@ export default class PanoBoxFrame extends THREE.Group {
 
                         let size = new THREE.Vector3(aveW, 2, aveW)
                         let c = 0
-                        infos.box = []
+                        infos.rowboxs = []
                         while (c < count) {
                             let center
                             if (k > 1) {
@@ -2537,7 +2587,7 @@ export default class PanoBoxFrame extends THREE.Group {
 
                             let box = new Box({ name: 'row' + i + '-' + c, center, size: size1, boxType: 'cabinet', infos })
                             c++
-                            infos.box.push(box)
+                            infos.rowboxs.push(box)
                         }
                     })
 
@@ -2640,15 +2690,15 @@ export default class PanoBoxFrame extends THREE.Group {
                 let datas = {}
                 let panoIds = []
                 for (let id in this.datas) {
-                    if(!this.datas[id])continue
-                    datas[id] = this.datas[id].shapes.filter(e => isType(e, type))
+                    if (!this.datas[id]) continue
+                    datas[id] = this.datas[id].shapes.filter(e => isType(e.category, type))
                     datas[id].length && panoIds.push(id)
                 }
 
                 for (let id in this.datas) {
                     //对data预处理
                     //(之后如果还出现不同类型重叠在一起的,需要先识别摘除下。 )4GqaqNdyjGf
-                    if(!this.datas[id])continue
+                    if (!this.datas[id]) continue
                     removeContain(datas[id]) //去除线框中的嵌套,主要是一个嵌套两个的。案例:KK-1Zjm9Rbl47
 
                     if (datas[id].length) {
@@ -2804,7 +2854,7 @@ export default class PanoBoxFrame extends THREE.Group {
                         waitFindRest.push({ type, args: [groups, 0] }) //等待最后检查遗漏
                         return
                     }
-                }
+                } 
 
                 //零散匹配。
                 let match2Group = (group0, group1, { fake }) => {
@@ -2826,11 +2876,12 @@ export default class PanoBoxFrame extends THREE.Group {
 
                     let newGroup0 = group0.slice(0)
                     let newGroup1 = group1.slice(0)
-                    while (newGroup1.length < newGroup0.length) {
+                    /* while (newGroup1.length < newGroup0.length) {
                         newGroup1.push({ sid: 'void' }) //为了使排列正确,补个空,使左右两边个数相等,过后和void匹配的不会计算box
-                    }
-
-                    searchPair(group0[0], newGroup0, newGroup1, null, resultPairs)
+                    } */
+                    
+                    let evaluateFun = getMatchScore.bind(this)
+                    searchPair(/* group0[0] */null, newGroup0, newGroup1, null, resultPairs, evaluateFun)
 
                     /* console.log(
                         'resultPairs',
@@ -3042,10 +3093,13 @@ export default class PanoBoxFrame extends THREE.Group {
                             //let r0 = solidBox.boxType == 'air' ? 2 : solidBox.boxType == 'battery' ? 1.1 : 1 //空调最不容易扎堆放置,所以范围设置广一些
                             let r0 = standards[box.boxType].closeRatio
 
-                            let r1 = math.linearClamp(box.pano.position.distanceTo(p2), 3, 8, 1, 2) //距离远的话识别、计算都会更不准确,给一定的容错. 远的尽量不findRest,即尽量>0
+                            let r1 = math.linearClamp(box.pano.position.distanceTo(p2), 3, 20, 1, 5) //距离远的话识别、计算都会更不准确,给一定的容错. 远的尽量不findRest,即尽量>0
 
                             let ra = (solidBox.boxType == box.boxType ? 1 : 0.5) * r0 * r1 //数字越小限制越大
-
+                
+if(box.sid == 'pano48-5'){
+    console.log(1)
+}
                             /* let a = maxWidth * maxWidth * ra - p1_.distanceToSquared(p2_)
                             let b = -dis * dis * 0.7  
                             let c = a + b*/
@@ -3426,16 +3480,16 @@ export default class PanoBoxFrame extends THREE.Group {
 
             let createSinglePano = (box, minScorePercent = 1) => {
                 //仅用一个pano中的data来创建。  悬挂于墙上的准确性依赖于墙的准确性。
-
+ 
                 if (box.score < MinBoxInitialScore) {
                     //如Xszq2fv03b的电池pano8-0其实是纸箱、 WZQoMbNmNTu的pano14-0分数0.649
-                    return console.error('取消createSinglePano: 线框识别分数低,可能错误', box)
+                    return console.error('取消createSinglePano: 线框识别分数低,可能错误', box.sid, box)
                 }
 
                 getBoxBase(box)
 
                 let center = getBoxPos(box)
-                if (safeBound.distanceToPoint(center) > 0.5) {
+                if (safeBound.distanceToPoint(center) > 0) {
                     return console.log('取消createSinglePano:超出safebound', box) //可能是错误的线框,如H7pg1tO9oeJ pano8-1
                 }
 
@@ -3524,7 +3578,7 @@ export default class PanoBoxFrame extends THREE.Group {
         })() */
         let done = () => {
             for (let panoId in this.datas) {
-                if(!this.datas[panoId])continue
+                if (!this.datas[panoId]) continue
                 this.datas[panoId].shapes = this.datas[panoId].shapes.map((shape, i) => {
                     return Object.assign(
                         {
@@ -3537,50 +3591,54 @@ export default class PanoBoxFrame extends THREE.Group {
                     )
                 })
             }
-            this.panoBound = new THREE.Box3()
-            player.model.chunks.forEach(e => {
-                modelBound.union(e.geometry.boundingBox) //注:不用model.boundingBox是 因为union了pano的position的
-            })
-            //针对部分模型错误,只有底面的,union一下pano.position
-
-            let minY = Infinity,
-                minYs = []
-            let panos = player.model.panos.list.filter(e => e.isAligned())
-            panos.forEach(e => {
-                let bound = new THREE.Box3().setFromCenterAndSize(e.position, new THREE.Vector3(0.1, 0.1, 0.1))
-                modelBound.union(bound)
-                this.panoBound.union(bound)
-                minY = Math.min(e.floorPosition.y, minY)
-                //avePanoFY += e.floorPosition.y
-                minYs.push(e.floorPosition.y)
-            })
 
-            groundY = modelBound.min.y
-            minYs.sort((a, b) => {
-                return a - b
-            })
-            console.log(minYs)
+            if (this.ifAnalyze) {
+                this.panoBound = new THREE.Box3()
+                player.model.chunks.forEach(e => {
+                    modelBound.union(e.geometry.boundingBox) //注:不用model.boundingBox是 因为union了pano的position的
+                })
+                //针对部分模型错误,只有底面的,union一下pano.position
+
+                let minY = Infinity,
+                    minYs = []
+                let panos = player.model.panos.list.filter(e => e.isAligned())
+                panos.forEach(e => {
+                    let bound = new THREE.Box3().setFromCenterAndSize(e.position, new THREE.Vector3(0.1, 0.1, 0.1))
+                    modelBound.union(bound)
+                    this.panoBound.union(bound)
+                    minY = Math.min(e.floorPosition.y, minY)
+                    //avePanoFY += e.floorPosition.y
+                    minYs.push(e.floorPosition.y)
+                })
 
-            let midFloorY = minYs[Math.floor(minYs.length / 2)]
-            console.error('minY', minY, 'midFloorY', midFloorY, '原groundY', groundY)
-            this.minY = minY
+                groundY = modelBound.min.y
+                minYs.sort((a, b) => {
+                    return a - b
+                })
+                console.log(minYs)
 
-            //部分模型底部高度错误
-            /* if (minY > groundY) {
-                console.error('minY > groundY', minY, groundY)
-                groundY = modelBound.min.y = midFloorY //案例nZrBdvRaDuC
-            } else {
-                if (groundY - minY > 0.05) console.warn('minY', minY, 'groundY', groundY)
-                groundY = modelBound.min.y = midFloorY   , document.title += ' new' //修改以后未必更好所以暂时不修改  变更好的:eGhyf5QdVHA
-            } */
-            groundY = modelBound.min.y = midFloorY //这个y可能不准。需要通过fire的btmPos.y来确定
-            safeBound = this.safeBound = modelBound
+                let midFloorY = minYs[Math.floor(minYs.length / 2)]
+                console.error('minY', minY, 'midFloorY', midFloorY, '原groundY', groundY)
+                this.minY = minY
 
-            groundPlane.setFromNormalAndCoplanarPoint(new THREE.Vector3(0, 1, 0), new THREE.Vector3(0, groundY, 0))
+                //部分模型底部高度错误
+                /* if (minY > groundY) {
+                    console.error('minY > groundY', minY, groundY)
+                    groundY = modelBound.min.y = midFloorY //案例nZrBdvRaDuC
+                } else {
+                    if (groundY - minY > 0.05) console.warn('minY', minY, 'groundY', groundY)
+                    groundY = modelBound.min.y = midFloorY   , document.title += ' new' //修改以后未必更好所以暂时不修改  变更好的:eGhyf5QdVHA
+                } */
+                groundY = modelBound.min.y = midFloorY //这个y可能不准。需要通过fire的btmPos.y来确定
+                safeBound = this.safeBound = modelBound
+
+                groundPlane.setFromNormalAndCoplanarPoint(new THREE.Vector3(0, 1, 0), new THREE.Vector3(0, groundY, 0))
 
-            this.ifAnalyze && beginCompute()
+                beginCompute()
+            }
             if (version == 'vision') this.load(player.currentPano.id)
         }
+
         async function load(panoId) {
             let data = await http.post('/service/scene/sceneMarkShape/getInfo', { num: player.$app.config.num, imagePath: panoId + '.jpg' })
             // console.error(data)
@@ -3593,12 +3651,40 @@ export default class PanoBoxFrame extends THREE.Group {
         }
         async function loadAll() {
             let data = await http.post('/service/shapes/sceneMarkShape/getInfos', { num: player.$app.config.num })
-            console.error(data)
+
             if (!data.data || !data.success) return
-            data.data.forEach(e => {
+
+            if (browser.urlHasValue('ext')) {
+                //利用算好的toJson的数据展示框
+                //console.log('box8',data.data)
+                data.data.box8.boxes.boxes.forEach(e => {
+                    let point1 = math.convertVisionVector(new THREE.Vector3().fromArray(e.points[0]))
+                    let point2 = math.convertVisionVector(new THREE.Vector3().fromArray(e.points[1]))
+                    let point3 = math.convertVisionVector(new THREE.Vector3().fromArray(e.points[2]))
+                    let point4 = math.convertVisionVector(new THREE.Vector3().fromArray(e.points[4]))
+
+                    let size = new THREE.Vector3(point1.distanceTo(point2), point1.y - point4.y, point3.distanceTo(point2))
+                    let center = new THREE.Vector3().addVectors(point3, point4).multiplyScalar(0.5) //对角线中点
+
+                    //可能需要考虑上rotation,现暂时不需要
+
+                    let box = new Box({
+                        buildFromData: true,
+                        center,
+                        size,
+                        boxType: e.type,
+                        name: e.sid,
+                    })
+                })
+                this.ifAnalyze = false
+            }
+
+            let box4 = Array.isArray(data.data) ? data.data : data.data.box4 // 兼容旧数据
+            box4.forEach(e => {
                 let panoId = e.imagePath.split('.jpg')[0]
                 this.datas[panoId] = e
             })
+
             done()
         }
 
@@ -3609,7 +3695,7 @@ export default class PanoBoxFrame extends THREE.Group {
                 panosCount++
                 load.bind(this)(e.id)
             }) */
-            
+
             loadAll.bind(this)() //测试环境
         } else {
             //when  version == 'output'
@@ -3630,9 +3716,11 @@ export default class PanoBoxFrame extends THREE.Group {
         let list = []
 
         for (let panoId in this.datas) {
-            if(!this.datas[panoId])continue
-            this.datas[panoId].shapes.forEach(box => {
-                getBoxBase(box)
+            if (!this.datas[panoId]) continue
+            let { imageWidth, imageHeight } = this.datas[panoId]
+                
+            this.datas[panoId].shapes.forEach((box) => {
+                getBoxBase(box, imageWidth, imageHeight )
                 if (box.sid == 'pano2-10') {
                     console.log(4)
                 }
@@ -3950,9 +4038,13 @@ export default class PanoBoxFrame extends THREE.Group {
             let pos = getBoxPos(shape)
             let dis = pos ? shape.pano.position.distanceTo(getBoxPos(shape)) : 1
             let labelShift = (shape.boxType == 'fire' ? 0 : -0.2) / dis
-
+            let name = shape.category + '-' + shape.sid
+            //if(shape.score < MinBoxInitialScore){
+                name = [name, 'sc: '+math.toPrecision(shape.score,3)]
+            //}
+            
             this.showSignalFrom2d(
-                shape.category + '-' + shape.sid,
+                name,
                 shape.bbox2,
                 imageWidth,
                 imageHeight,
@@ -4056,18 +4148,9 @@ export default class PanoBoxFrame extends THREE.Group {
             lineMaterial.color.set('#efe')
         }
     }
-    
-    
-    clear(){//清除上一次的结果 
-        skyBoxTight = null,
-        meshGroup = null,
-        modelBound = new THREE.Box3(),  
-        groundY = null,  safeBound = null,  boundConfirmed = null,  
-        hue = 0,
-        boxesSolid = []
+
+    clear() {
+        //清除上一次的结果
+        ;(skyBoxTight = null), (meshGroup = null), (modelBound = new THREE.Box3()), (groundY = null), (safeBound = null), (boundConfirmed = null), (hue = 0), (boxesSolid = [])
     }
-    
-    
-    
-    
-}
+}