|
@@ -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 = [])
|
|
|
}
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-}
|
|
|
+}
|