瀏覽代碼

Merge branch 'master' of http://192.168.0.115:3000/bill/fuse-code

bill 3 年之前
父節點
當前提交
df844b62e0

+ 217 - 116
public/lib/potree/potree.js

@@ -63567,17 +63567,17 @@ void main() {
         };
         
         
-        /* var transformPointcloud = (pointcloud )=>{ //初始化位置  
-            viewer.sidebar && viewer.sidebar.addAlignmentButton(pointcloud) 
+        var transformPointcloud = (pointcloud )=>{ //初始化位置  
+            viewer.sidebar && viewer.sidebar.addAlignmentButton(pointcloud); 
              
-            let orientation = pointcloud.panos[0].dataRotation.z
-            let location = pointcloud.panos[0].dataPosition.clone().negate()
-            Alignment.rotate(pointcloud, null,  orientation  )   
-            Alignment.translate(pointcloud, location )  
+            let orientation = pointcloud.panos[0].dataRotation.z;
+            let location = pointcloud.panos[0].dataPosition.clone().negate();
+            Alignment.rotate(pointcloud, null,  orientation  );   
+            Alignment.translate(pointcloud, location );  
             
-            pointcloud.updateMatrixWorld()
+            pointcloud.updateMatrixWorld();
               
-        }  */ 
+        };   
          
          
          
@@ -63680,7 +63680,7 @@ void main() {
         }
         
         Potree.settings.sizeFitToLevel = true;//当type为衰减模式时自动根据level调节大小。每长一级,大小就除以2
-        Potree.loadPointCloudScene = function(sceneCode, done){//对应4dkk的场景码
+        Potree.loadPointCloudScene = function(sceneCode, done, onError){//对应4dkk的场景码
             Potree.loadDatasets((data)=>{
                 var originDataset = data.find(e=>e.sceneCode == sceneCode);//只加载初始数据集  
                 var cloudPath = `${Potree.settings.urls.prefix}/${Potree.settings.webSite}/${sceneCode}/data/${sceneCode}/webcloud/cloud.js`; 
@@ -63722,10 +63722,10 @@ void main() {
                     viewer.scene.add360Images(viewer.images360);    */   
                     viewer.dispatchEvent('allLoaded');
                     done(pointcloud);
-                }); 
+                },onError); 
                     
                 
-            }, sceneCode);      
+            }, sceneCode, onError);      
              
              
         }; 
@@ -63787,7 +63787,7 @@ void main() {
          
         
         let modelType,  modelEditing, MergeEditor = viewer.modules.MergeEditor;
-        Potree.addModel = function(prop, done, onprogress){ //加载模型
+        Potree.addModel = function(prop, done, onProgress, onError){ //加载模型
             let isFirstLoad = !prop.position; //在编辑时用户添加的
         
             let loadDone = (model)=>{ 
@@ -63865,7 +63865,7 @@ void main() {
                         viewer.outlinePass.selectedObjects = []
                     }) */
                     
-                });
+                }, onError);
             }else {
                 
                  
@@ -63906,17 +63906,23 @@ void main() {
                     loadDone(object);
                 };
                 
-                 
-                viewer.loadModel({ 
-                    name: 'glb', 
-                    glburl: prop.url,  //0.3s
+                
+                let info = {
+                    name: prop.type, 
                     transform : { 
                         position : prop.position,
                         rotation : new Euler().setFromVector3(prop.rotation), 
                         scale: new Vector3(prop.scale,prop.scale,prop.scale),        
-                    } 
-                    
-                },callback,onprogress);
+                    }                
+                };
+                
+                if(prop.type == 'glb'){
+                    info.glburl = prop.url;  
+                }else {
+                    info.objurl = prop.url;
+                    info.mtlurl = prop.mtlurl;
+                } 
+                viewer.loadModel(info , callback, onProgress, onError);
                 
             }
         };
@@ -84014,6 +84020,7 @@ void main() {
                       
                         let pointclouds;
                         let Alignment = window.viewer.modules.Alignment;
+                        let MergeEditor = window.viewer.modules.MergeEditor;
                         let handleState = Alignment.handleState;
                         
                         let a = e.buttons === Buttons.LEFT && viewport.alignment && handleState && viewport.alignment[handleState]; 
@@ -84033,8 +84040,13 @@ void main() {
                             }
                             
                             if(!pointclouds && e.buttons === Buttons.LEFT && viewport.alignment.rotateSide){
-                                return PanoEditor.rotateSideCamera(e.drag.pointerDelta.x)
+                                return PanoEditor.rotateSideCamera(-e.drag.pointerDelta.x)
                             }
+                        }else if(Potree.settings.editType == 'merge'){ 
+                            if(e.buttons === Buttons.LEFT && viewport.alignment.rotateSide){ 
+                                return MergeEditor.rotateSideCamera(-e.drag.pointerDelta.x)
+                            }
+                        
                         }else { 
                             /* if(Alignment.selectedClouds && Alignment.selectedClouds.length){
                                 pointclouds = a && e.drag.intersectStart.pointclouds && Common.getMixedSet(Alignment.selectedClouds, e.drag.intersectStart.pointclouds).length && Alignment.selectedClouds
@@ -84744,6 +84756,7 @@ void main() {
     			this.domElement.tabIndex = 2222;
     		}
             
+            this.lastPointerUpTime = 0;
             
             this.touches = [];
 
@@ -84766,7 +84779,7 @@ void main() {
     		this.domElement.addEventListener('mousewheel', this.onMouseWheel.bind(this), false);
     		this.domElement.addEventListener('DOMMouseScroll', this.onMouseWheel.bind(this), false); // Firefox
             
-    		this.domElement.addEventListener('dblclick', this.onDoubleClick.bind(this)); 
+    		//this.domElement.addEventListener('dblclick', this.onDoubleClick.bind(this));  //因为双击时间间隔是跟随系统的所以不好判断
     		
             this.domElement.addEventListener('keydown', this.onKeyDown.bind(this));
     		window.addEventListener('keyup', this.onKeyUp.bind(this));
@@ -85057,7 +85070,7 @@ void main() {
     				});
     			//}
     		}
-
+            this.needSingleClick = false;//add
     		e.preventDefault();
     	}
 
@@ -85215,6 +85228,7 @@ void main() {
             if(isTouch && e.touches.length >= 1){ 
                 return
             }
+            let now = Date.now();
             
             
     		if (this.logMessages) console.log(this.constructor.name + ': onMouseUp');
@@ -85222,7 +85236,7 @@ void main() {
     		e.preventDefault();
             
             let pressDistance = this.mouseDownMouse.distanceTo(this.mouse);
-            let pressTime = Date.now() - this.pointerDownTime;
+            let pressTime = now - this.pointerDownTime;
             
     		let noMovement = this.drag.pointerDelta.length() == 0;//this.getNormalizedDrag().length() === 0;
             
@@ -85301,7 +85315,9 @@ void main() {
                                     pressDistance     
                                 }
                             )); 
-                        }  
+                        }
+                        
+                        
                     }
                     
                     //if(!clickElement){
@@ -85312,7 +85328,32 @@ void main() {
                                 pressDistance
                             }
                         )); 
-                    //} 
+                    //}
+                    
+                    
+                    
+                    //增加 单击:
+                    this.needSingleClick = true;
+                    this.doubleClickTime = 200; //双击间隔时间
+                    setTimeout(()=>{
+                        if(this.needSingleClick){
+                            this.viewer.dispatchEvent($.extend(  
+                                this.getEventDesc(e,isTouch),
+                                {
+                                    type: 'global_single_click',  
+                                    pressDistance
+                                }
+                            ));
+                        }
+                    }, this.doubleClickTime+1);
+                    
+                    //自行执行双击:
+                    
+                    if(now - this.lastClickTime < this.doubleClickTime){
+                        this.onDoubleClick(e);
+                    }
+                    
+                    this.lastClickTime = now;
                 }
                 
     			 
@@ -85347,6 +85388,8 @@ void main() {
     				this.deselectAll();
     			}
     		}
+            
+            
         }
         
     	onMouseUp (e) {
@@ -103286,7 +103329,10 @@ ENDSEC
             } 
             if(!I)return;
             
-            viewer.setView({position:I, duration:1000});
+            let dis = this.scene.view.position.distanceTo(I);
+            let distance = MathUtils.clamp(dis, 0.3, 3);
+            
+            viewer.focusOnObject({ position:I }, 'point', null, {distance});
             
         }
 
@@ -111971,29 +112017,26 @@ ENDSEC
             viewer.updateScreenSize({forceUpdateSize:true});        
         }
         
-        viewportFitBound(viewport,  bound,  center, duration=0){
+        viewportFitBound(viewport,  bound,  center, duration=0, margin){
             let view = viewport.view;
             let info = {bound}; 
              
             viewport.targetPlane.setFromNormalAndCoplanarPoint( view.direction.clone(), viewer.bound.center );  
             viewport.targetPlane.projectPoint(center, viewport.shiftTarget);  //target转换到过模型中心的平面,以保证镜头一定在模型外 this.shiftTarget是得到的
             
-            info.endPosition = this.getPosOutOfModel(viewport.shiftTarget, view ); 
+            info.endPosition = this.getPosOutOfModel(viewport); 
             
             //if(viewport.name == 'mapViewport')info.endPosition.z = Math.max(Potree.config.map.cameraHeight, info.endPosition.z) 
-            
              
-        
-        
-            info.margin = {x:30, y:30};    
+            info.margin = margin || {x:30, y:30};    
             view.moveOrthoCamera(viewport, info ,  duration   );
         } 
         
-        getPosOutOfModel(shiftTarget, view){
+        getPosOutOfModel(viewport){ 
             let {boundSize, center} = viewer.bound;
             let expand = 10; 
             let radius = boundSize.length() / 2;  
-            let position = shiftTarget.clone().sub(view.direction.clone().multiplyScalar(radius + expand));  
+            let position = viewport.shiftTarget.clone().sub(viewport.view.direction.clone().multiplyScalar(radius + expand));  
              
             return position 
         } 
@@ -112011,7 +112054,28 @@ ENDSEC
             });  
         }  
          
-        
+        rotateSideCamera(viewport, angle){//侧视图绕模型中心水平旋转
+             
+            let {boundSize, center} = viewer.bound;
+              
+            //找到平移向量
+            viewport.targetPlane.setFromNormalAndCoplanarPoint(viewport.view.direction  , center ); 
+            viewport.targetPlane.projectPoint(viewport.view.position,  viewport.shiftTarget );  //target转换到过模型中心的平面,以保证镜头一定在模型外
+            let vec = new Vector3().subVectors(center, viewport.shiftTarget);//相对于中心的偏移值,旋转后偏移值也旋转
+            
+            //旋转
+            var rotMatrix = new Matrix4().makeRotationAxis(new Vector3(0,0,1), angle); 
+            
+            viewport.view.direction = viewport.view.direction.applyMatrix4(rotMatrix);
+             
+             
+            vec.applyMatrix4(rotMatrix);
+            viewport.shiftTarget.subVectors(center,vec); //新的
+            
+            
+            viewport.view.position = this.getPosOutOfModel(viewport);
+            
+        }
         
         getOrthoCamera(){
             return new OrthographicCamera(-100, 100, 100, 100, 0.01, 10000)
@@ -115021,7 +115085,7 @@ ENDSEC
             
             
             
-            viewer.addEventListener('global_click',(e)=>{
+            viewer.addEventListener('global_single_click',(e)=>{
                 if(viewer.inputHandler.selection[0] ||//正在平移和旋转,不允许更换
                     viewer.scene.cameraAnimations.length  //正在播放
                 ){
@@ -115044,17 +115108,20 @@ ENDSEC
         },
         
         
-        enterSplit(){
+        enterSplit(){ 
             this.SplitScreen.splitStart(viewportProps$1);
-            
-            
+            viewer.setControls(viewer.fpControls);  
+            viewer.viewports.find(e=>e.name == 'right').alignment = {rotateSide : true};
         },
         
         leaveSplit(){
             this.SplitScreen.unSplit();    
+            viewer.setControls(viewer.orbitControls); 
         },
         
-        
+        rotateSideCamera(angle){
+            this.SplitScreen.rotateSideCamera(viewer.viewports.find(e=>e.name == 'right'), angle);
+        },
         
         //---------------------------
         
@@ -115112,28 +115179,32 @@ ENDSEC
         },
         
         
-        focusOnSelect(object, duration = 400){  
-            let boundingBox = object.boundingBox.clone().applyMatrix4(object.matrixWorld);
-            let center = boundingBox.getCenter(new Vector3);
-            let size = boundingBox.getSize(new Vector3); 
-            let maxSize = size.length(); //对角线长度
+        /* focusOnSelect(object, duration = 400){  
+            let boundingBox = object.boundingBox.clone().applyMatrix4(object.matrixWorld)
+            let center = boundingBox.getCenter(new THREE.Vector3)
+            let size = boundingBox.getSize(new THREE.Vector3) 
+            let maxSize = size.length() //对角线长度
             
             if(object.isPointcloud){
-                maxSize /= 2;
+                maxSize /= 2
             }
             
-            let hfov = cameraLight.getHFOVForCamera(viewer.mainViewport.camera,true);
-            let minRadius = maxSize  / Math.tan(hfov/2);
+            let hfov = cameraLight.getHFOVForCamera(viewer.mainViewport.camera,true)
+            let minRadius = maxSize  / Math.tan(hfov/2)
             //viewer.mainViewport.view.lookAt(center)
             viewer.mainViewport.view.setView({  
                 position: center.clone().sub(viewer.mainViewport.view.direction.clone().multiplyScalar(minRadius)),
                 target: center,
                 duration 
-            });  //setView can cancel bump
+            })  //setView can cancel bump
+             
+        }, */
+        focusOnSelect(object, duration = 400){  
+            let boundingBox = object.boundingBox.clone().applyMatrix4(object.matrixWorld);
+            viewer.focusOnObject({boundingBox}, 'boundingBox', duration  );  
              
         },
         
-        
         setModelBtmHeight(model, z ){ 
             
             //无论模型怎么缩放、旋转,都使最低点为z
@@ -118767,7 +118838,7 @@ ENDSEC
         }  
     ];   
 
-    const targetPlane = new Plane();
+     
 
 
 
@@ -118786,8 +118857,7 @@ ENDSEC
             this.orthoCamera = new OrthographicCamera(-100, 100, 100, 100, 0.01, 10000);
             this.selectedPano;
             this.selectedGroup;
-            this.operation;
-            this.shiftTarget = new Vector3; //project在targetPlane上的位置
+            this.operation; 
             this.visiblePanos = [];
         }
          
@@ -118841,7 +118911,7 @@ ENDSEC
                 
                 
                 
-                this.switchView('top');
+                this.switchView('right'/* 'top' */);
                 
                 SiteModel$1.bus.addEventListener('initDataDone',()=>{ 
                     this.gotoFloor(SiteModel$1.entities.find(e=>e.buildType == 'floor'));  //任意一层
@@ -118918,13 +118988,18 @@ ENDSEC
         
          
         //////////////////////////////////
-        initViews(){ 
+        initViews(){
+            this.splitScreenTool = new SplitScreen;
+            this.targetPlane = viewer.mainViewport.targetPlane = new Plane();
+            this.shiftTarget = viewer.mainViewport.shiftTarget = new Vector3; //project在targetPlane上的位置
+             
+            
             for(let i=0;i<2;i++){
                 let prop = cameraProps[i];
                 let view = new View();  
                 this.views[prop.name] = view; 
                 this.cameras[prop.name] = this.orthoCamera;
-                
+                 
                 view.direction = prop.direction;
             }
             this.views.mainView = viewer.mainViewport.view;
@@ -118943,14 +119018,15 @@ ENDSEC
             this.activeViewName = name; 
             let lastView = this.views[this.lastViewName];
             let lastCamera = this.cameras[this.lastViewName];
-            
-            //let aspect = viewer.mainViewport.camera.aspect
             viewer.mainViewport.view = view;
             viewer.mainViewport.camera = camera; 
-            //targetPlane.setFromNormalAndCoplanarPoint( prop.direction.clone(), center ) 
-            targetPlane.setFromNormalAndCoplanarPoint( view.direction.clone(), center );  
-            targetPlane.projectPoint(view.position, this.shiftTarget );  //target转换到过模型中心的平面,以保证镜头一定在模型外
-            view.position.copy(this.getPosOutOfModel());
+            if(lastCamera)lastView.zoom = lastCamera.zoom;
+            
+            this.targetPlane.setFromNormalAndCoplanarPoint( view.direction.clone(), center );  
+            this.targetPlane.projectPoint(view.position, this.shiftTarget );  //target转换到过模型中心的平面,以保证镜头一定在模型外
+            view.position.copy(this.splitScreenTool.getPosOutOfModel(viewer.mainViewport));
+            if(view.zoom)camera.zoom = view.zoom;//恢复上次的zoom
+             
             
             viewer.updateScreenSize({forceUpdateSize:true});//更新camera aspect  left等
             this.updateCursor();
@@ -118981,13 +119057,12 @@ ENDSEC
                     
                     console.log('最近',nearestPano );
                     
-                    if(nearestPano && nearestPano[0] ){
-                      
-                        
+                    if(nearestPano && nearestPano[0] ){ //尽量不变画面范围,使pano点保持原位,转换到mainView
                         let halfHeight = lastCamera.top/lastCamera.zoom; 
                         let dis = halfHeight / Math.tan( MathUtils.degToRad(camera.fov/2)); 
                         view.position.add(direction.clone().multiplyScalar(-nearestPano[0].score - dis));
-                        console.log('getCloser', -nearestPano[0].score - dis);
+                        //console.log('getCloser', -nearestPano[0].score - dis)
+                        this.lastDisToPano = dis; //记录一下
                     }
                     
                 }
@@ -119014,7 +119089,9 @@ ENDSEC
                 viewer.updateVisible(viewer.reticule, 'force', false);      
                 
                 if(name == 'top') viewer.mainViewport.alignment = {rotate:true,translate:true};
-                else if(name == 'right') viewer.mainViewport.alignment = {translate:true, rotateSide:true};
+                if(name == 'right'){
+                    viewer.mainViewport.alignment = {translate:true, rotateSide:true}; 
+                }
                 
             } 
             
@@ -119024,7 +119101,7 @@ ENDSEC
         
         //new THREE.Plane().setFromNormalAndCoplanarPoint( normal, this.points[0]  )
         
-        viewportFitBound(name, boundSize_, target){  //使一个viewport聚焦在某个范围
+        viewportFitBound(/* name, boundSize_, target */){  //使一个viewport聚焦在某个范围
             /* let viewport = viewer.mainViewport 
             let {boundSize, center} = viewer.bound
         
@@ -119058,7 +119135,7 @@ ENDSEC
             
             if(viewer.mainViewport.resolution.x == 0 || viewer.mainViewport.resolution.y == 0){
                 return setTimeout(()=>{
-                    this.viewportFitBound(name, boundSize_, target);
+                    this.viewportFitBound(/* name, boundSize_, target */);
                 },10)
             }
              
@@ -119068,46 +119145,48 @@ ENDSEC
         } 
         
         
-        
-        
         rotateSideCamera(angle){//侧视图绕模型中心水平旋转
-            var prop = cameraProps.find(v => v.name == 'right' );
+             this.splitScreenTool.rotateSideCamera(viewer.mainViewport, angle); 
+        }
+        
+        /* rotateSideCamera(angle){//侧视图绕模型中心水平旋转
+            var prop = cameraProps.find(v => v.name == 'right' )
             
-            let {boundSize, center} = viewer.bound;
+            let {boundSize, center} = viewer.bound
              
              
             //找到平移向量
-            targetPlane.setFromNormalAndCoplanarPoint(viewer.mainViewport.view.direction /* prop.direction.clone() */, center ); 
-            targetPlane.projectPoint(viewer.mainViewport.view.position,  this.shiftTarget );  //target转换到过模型中心的平面,以保证镜头一定在模型外
-            let vec = new Vector3().subVectors(center, this.shiftTarget);//相对于中心的偏移值,旋转后偏移值也旋转
+            targetPlane.setFromNormalAndCoplanarPoint(viewer.mainViewport.view.direction  , center ) 
+            targetPlane.projectPoint(viewer.mainViewport.view.position,  this.shiftTarget )  //target转换到过模型中心的平面,以保证镜头一定在模型外
+            let vec = new THREE.Vector3().subVectors(center, this.shiftTarget)//相对于中心的偏移值,旋转后偏移值也旋转
             
             //旋转
-            var rotMatrix = new Matrix4().makeRotationAxis(new Vector3(0,0,1), angle); 
+            var rotMatrix = new THREE.Matrix4().makeRotationAxis(new THREE.Vector3(0,0,1), angle) 
             //prop.direction.applyMatrix4(rotMatrix)
-            viewer.mainViewport.view.direction = viewer.mainViewport.view.direction.applyMatrix4(rotMatrix);
+            viewer.mainViewport.view.direction = viewer.mainViewport.view.direction.applyMatrix4(rotMatrix)
              
              
-            vec.applyMatrix4(rotMatrix);
-            this.shiftTarget.subVectors(center,vec); //新的
+            vec.applyMatrix4(rotMatrix)
+            this.shiftTarget.subVectors(center,vec) //新的
             
             
-            viewer.mainViewport.view.position = this.getPosOutOfModel();
-            //this.setCameraPose(/* this.shiftTarget, prop.direction */)
+            viewer.mainViewport.view.position = this.splitScreenTool.getPosOutOfModel(viewer.mainViewport)  // this.getPosOutOfModel()
+      
             
-        }
+        } */
          
         
-        getPosOutOfModel(){//已知shiftTarget和currentDir后
-            let {boundSize, center} = viewer.bound;
+        /* getPosOutOfModel(){//已知shiftTarget和currentDir后
+            let {boundSize, center} = viewer.bound
             let expand = 10;
-            let view = viewer.mainViewport.view;
-            let radius = boundSize.length() / 2;  
-            let position = this.shiftTarget.clone().sub(view.direction.clone().multiplyScalar(radius + expand));  
+            let view = viewer.mainViewport.view
+            let radius = boundSize.length() / 2  
+            let position = this.shiftTarget.clone().sub(view.direction.clone().multiplyScalar(radius + expand))  
              
             return position 
              
             
-        }
+        } */
         
         zoomIn(intersectPoint, pointer){ 
             let camera = viewer.mainViewport.camera;
@@ -119125,12 +119204,14 @@ ENDSEC
             let radius = boundSize.length() / 2  
             return radius + expand 
         } */
-        moveFit(pos, info, duration){ 
-            targetPlane.projectPoint(pos, this.shiftTarget);  //target转换到过模型中心的平面,以保证镜头一定在模型外 this.shiftTarget是得到的
-            info.endPosition = this.getPosOutOfModel(); 
-            info.margin = {x:200, y:230};      
-            let view = viewer.mainViewport.view; 
-            view.moveOrthoCamera(viewer.mainViewport, info ,  duration   );
+        moveFit(pos, info, duration){  
+            var margin = {x:200, y:230};      
+            this.splitScreenTool.viewportFitBound(viewer.mainViewport,  info.bound,  pos, duration, margin );
+            /* targetPlane.projectPoint(pos, this.shiftTarget)  //target转换到过模型中心的平面,以保证镜头一定在模型外 this.shiftTarget是得到的
+            info.endPosition = this.getPosOutOfModel() 
+            info
+            let view = viewer.mainViewport.view 
+            view.moveOrthoCamera(viewer.mainViewport, info ,  duration   ) */
      
         }
         
@@ -119592,8 +119673,9 @@ ENDSEC
         selectPano(pano, informinformBy2d, force){
             if(this.selectedPano == pano && !force)return
             
-             
+            let lastSeletedPano = this.selectedPano;
             if(this.selectedPano){ 
+                
                 this.selectedPano.circle.material = circleMats.default; 
                 this.selectedPano.circle.renderOrder = renderOrders.circle; 
 
@@ -119648,9 +119730,21 @@ ENDSEC
 
 
 
-
-            informinformBy2d || this.dispatchEvent({type:'panoSelect', pano });
-            
+            if(informinformBy2d){
+                if(this.selectedPano){
+                    if(this.activeViewName == 'mainView'){ //平移,focus选中的pano
+                        let distance = this.lastDisToPano || 5; 
+                        if(lastSeletedPano){
+                            distance = viewer.mainViewport.camera.position.distanceTo(lastSeletedPano.position);
+                        }
+                        viewer.focusOnObject({ position:this.selectedPano.position}, 'point', null, {distance });
+                    }else {
+                        this.moveFit(this.selectedPano.position, {}, 500);
+                    }
+                } 
+            }else {
+                this.dispatchEvent({type:'panoSelect', pano });
+            } 
         }
         
         
@@ -126481,7 +126575,7 @@ ENDSEC
                     this.boundBox = new Mesh(new BoxGeometry(1,1,1,1));
                     this.boundBox.material.wireframe = true;
                     this.boundBox.up.set(0,0,1);
-                    this.boundBox.visible = false; //打开以检查box
+                    viewer.updateVisible(this.boundBox, 'hidden', false);//打开以检查box 
                     this.setObjectLayers(this.boundBox,'sceneObjects');
                     this.scene.scene.add(this.boundBox); 
                 }
@@ -127257,7 +127351,7 @@ ENDSEC
         }
          */
 
-        loadModel(fileInfo, done, onProgress_){ 
+        loadModel(fileInfo, done, onProgress_, onError){ 
             let boundingBox = new Box3();
             if(!Potree.settings.boundAddObjs){
                boundingBox.min.set(-0.5,-0.5,-0.5); boundingBox.max.set(0.5,0.5,0.5); 
@@ -127348,7 +127442,8 @@ ENDSEC
                     console.log( item, loaded, total );
                 }; */
                 
-                let onError = function ( xhr ) {};
+                /* let onError = function ( xhr ) { 
+                }; */
                 
                 loaders.mtlLoader.load( fileInfo.mtlurl , (materials)=>{ 
                     materials.preload(); 
@@ -127356,14 +127451,14 @@ ENDSEC
                     loaders.objLoader.setMaterials( materials ).load(fileInfo.objurl, (object)=>{   
                         loadDone(object);
                     });
-                } , onProgress, /*onError */ );  
+                } , onProgress,  onError  );  
                 
             }else if(fileType == 'glb'){
                 loaders.glbLoader.load(fileInfo.glburl,  ( gltf )=>{     //.setPath( Potree.resourcePath + '/models/glb/'  );
                  
                     console.log('loadGLTF', gltf);
                     loadDone(gltf.scene); 
-                }, onProgress);
+                }, onProgress, onError);
                 
             }
             
@@ -128142,24 +128237,29 @@ ENDSEC
 
 
 
-    async function loadFile(path, callback){
+    async function loadFile(path, callback, onError){
         if(Potree.fileServer){
             Potree.fileServer.get(path).then(data=>{ 
                 callback && callback(data);
-            });
+            }).fail(onError);
         }else {
-            let response = await fetch(path); 
-            let text = await response.text();
-            var data = JSON.parse(text);
-            if(data.data) data = data.data;
-            callback && callback(data); 
-            return data
+            try{
+                let response = await fetch(path); 
+                let text = await response.text();
+                var data = JSON.parse(text);
+                if(data.data) data = data.data;
+                callback && callback(data);    
+                return data 
+            }catch(e){
+                onError && onError(e);
+            }
+              
         }
         
         //查询: http://192.168.0.26:8080/doc.html#/default/filter-%E6%BC%AB%E6%B8%B8%E7%82%B9/filterUsingGET    
     }
 
-    async function loadDatasets(callback,sceneCode){//之后直接把path写进来
+    async function loadDatasets(callback,sceneCode,onError){//之后直接把path写进来
         let path; 
         sceneCode = sceneCode || Potree.settings.number;
         if(Potree.fileServer){
@@ -128172,7 +128272,7 @@ ENDSEC
             //path = `${Potree.scriptPath}/data/${sceneCode}/getDataSet.json`
             
         }
-        return loadFile(path, callback)
+        return loadFile(path, callback,onError)
         
     }
 
@@ -128307,7 +128407,7 @@ ENDSEC
 
      
 
-    function loadPointCloud$1(path, name, sceneCode, timeStamp, callback){
+    function loadPointCloud$1(path, name, sceneCode, timeStamp, callback, onError){
     	let loaded = function(e){
     		e.pointcloud.name = name;
             e.pointcloud.sceneCode = sceneCode; //对应4dkk的场景码
@@ -128336,6 +128436,7 @@ ENDSEC
     				if (!geometry) {
     					//callback({type: 'loading_failed'});
     					console.error(new Error(`failed to load point cloud from URL: ${path}`));
+                        onError && onError();
     				} else {
     					let pointcloud = new PointCloudOctree(geometry);
     					// loaded(pointcloud);

文件差異過大導致無法顯示
+ 1 - 1
public/lib/potree/potree.js.map


+ 10 - 4
src/api/constant.ts

@@ -22,10 +22,16 @@ export const UPDATE_MODEL = `/laser/sceneFusion/${params.m}/updateModel`
 export const DELETE_MODEL = `/laser/sceneFusion/${params.m}/del`
 
 // 标注列表
-export const TAGGING_LIST = ''
-export const INSERT_TAGGING = ''
-export const UPDATE_TAGGING = ''
-export const DELETE_TAGGING = ''
+export const TAGGING_LIST = `/laser/sceneTag/${params.m}/list/${params.fushId}`
+export const INSERT_TAGGING = `/laser/sceneTag/${params.m}/add`
+export const UPDATE_TAGGING = `/laser/sceneTag/${params.m}/edit`
+export const DELETE_TAGGING = `/laser/sceneTag/${params.m}/delete`
+
+// 标注放置列表
+export const TAGGING_POINT_LIST = `/laser/caseTagPoint/${params.m}/list/`
+export const INSERT_TAGGING_POINT = `/laser/caseTagPoint/${params.m}/place`
+export const UPDATE_TAGGING_POINT = `/laser/sceneTag/${params.m}/edit`
+export const DELETE_TAGGING_POINT = `/laser/caseTagPoint/${params.m}/delete`
 
 // 标注样式类型列表
 export const TAGGING_STYLE_LIST = ''

+ 1 - 0
src/api/index.ts

@@ -7,5 +7,6 @@ export * from './instance'
 export * from './model'
 export * from './tagging'
 export * from './tagging-style'
+export * from './tagging-position'
 export * from './guide'
 export * from './sys'

+ 14 - 5
src/api/instance.ts

@@ -1,7 +1,8 @@
 import { axiosFactory } from './setup'
 import { Message } from 'bill/index'
-import { ResCodeDesc, MODEL_LIST, UPDATE_MODEL, INSERT_MODEL, DELETE_MODEL } from './constant'
 import { showLoad, hideLoad } from '@/utils'
+import * as URL from './constant'
+import { ResCode, ResCodeDesc } from './constant'
 
 const instance = axiosFactory()
 
@@ -39,10 +40,18 @@ addResErrorHandler(
 addHook({ before: showLoad, after: hideLoad })
 
 addUnsetTokenURLS(
-  MODEL_LIST,
-  UPDATE_MODEL,
-  INSERT_MODEL,
-  DELETE_MODEL
+  URL.MODEL_LIST,
+  URL.UPDATE_MODEL,
+  URL.INSERT_MODEL,
+  URL.DELETE_MODEL,
+  URL.TAGGING_LIST,
+  URL.DELETE_TAGGING,
+  URL.INSERT_TAGGING,
+  URL.UPDATE_TAGGING,
+  URL.TAGGING_POINT_LIST,
+  URL.INSERT_TAGGING_POINT,
+  URL.UPDATE_TAGGING_POINT,
+  URL.DELETE_TAGGING_POINT,
 )
 setDefaultURI('/api')
 

+ 4 - 32
src/api/model.ts

@@ -50,6 +50,7 @@ interface ServiceModel {
   modelTitle: string
   opacity: number
   bottom: number
+  type: number
   transform: {
     position: SceneLocalPos, 
     rotation: SceneLocalPos, 
@@ -68,7 +69,7 @@ const serviceToLocal = (serviceModel: ServiceModel): Model => ({
   url: serviceModel.modelGlbUrl,
   title: serviceModel.modelTitle,
   fusionId: serviceModel.fusionId,
-  type: ModelType.SWMX,
+  type:  serviceModel.type === 2 ? ModelType.SWSS : ModelType.SWMX,
   size: serviceModel.modelSize,
   time: serviceModel.createTime
 })
@@ -80,6 +81,7 @@ const localToService = (model: Model): ServiceModel => ({
   fusionId: model.fusionId,
   modelDateType: model.type,
   modelGlbUrl: model.url,
+  type: model.type === ModelType.SWSS ? 2 : 3,
   modelSize: model.size,
   modelTitle: model.title,
   opacity: model.opacity,
@@ -96,36 +98,6 @@ export type Models = Model[]
 export const fetchModels = async () => {
   const serviceModels = await axios.post<ServiceModel[]>(MODEL_LIST)
   return serviceModels.map(serviceToLocal)
-  return [
-    {
-      id: '123',
-      url: 'SS-t-7DUfWAUZ3V',
-      type: ModelType.SWSS,
-      title: 'SS-t-7DUfWAUZ3V',
-      size: 1000,
-      time: '2012-02-05',
-      rotation: { x: 1, y: 1, z: 1},
-      position: { x: 1, y: 1, z: 1},
-      opacity: 0.1,
-      scale: 1,
-      bottom: 1,
-      show: false
-    },
-    {
-      id: '124',
-      url: '/lib/resources/models/glb/coffeemat.glb',
-      type: ModelType.SWMX,
-      title: '某安外',
-      size: 1000,
-      time: '2012-02-05',
-      scale: 1,
-      rotation: { x: 1, y: 1, z: 1},
-      position: { x: 1, y: 1, z: 1},
-      opacity: 0.1,
-      bottom: 1,
-      show: true
-    }
-  ]
 } 
 
 export const postAddModel = async (file: File) => {
@@ -149,7 +121,7 @@ export const postUpdateModels = (model: Model) => {
 
 export const postDeleteModel = (id: Model['id']) => {
   console.log('delete')
-  return axios.post<undefined>(DELETE_MODEL)
+  return axios.post<undefined>(DELETE_MODEL, {ids: [id]})
 }
 
   

+ 5 - 5
src/api/setup.ts

@@ -132,11 +132,11 @@ export const axiosFactory = () => {
 
       if (!matchURL(axiosConfig.unTokenSet, config)) {
         if (!axiosConfig.token) {
-          if (!matchURL(axiosConfig.unReqErrorSet, config)) {
-            const error = new Error('缺少token')
-            callErrorHandler('req', error, config)
-            throw error
-          }
+          // if (!matchURL(axiosConfig.unReqErrorSet, config)) {
+          //   const error = new Error('缺少token')
+          //   callErrorHandler('req', error, config)
+          //   throw error
+          // }
         } else {
           config.headers = {
             ...config.headers,

+ 62 - 0
src/api/tagging-position.ts

@@ -0,0 +1,62 @@
+import axios from './instance'
+import { 
+  TAGGING_POINT_LIST,
+  DELETE_TAGGING_POINT,
+  UPDATE_TAGGING_POINT,
+  INSERT_TAGGING_POINT
+} from './constant'
+
+import type { Model } from './model'
+import type { Tagging } from './tagging'
+
+interface ServicePosition {
+  "id": number,
+  "tagId": number,
+  "modelId": number
+  "tagPoint": SceneLocalPos,
+}
+
+export interface TaggingPosition {
+  id: string,
+  taggingId: Tagging['id']
+  modelId: Model['id']
+  localPos: SceneLocalPos
+}
+
+export type TaggingPositions = TaggingPosition[]
+
+
+const serviceToLocal = (position: ServicePosition, taggingId?: Tagging['id']): TaggingPosition => ({
+  id: position.id.toString(),
+  modelId: position.modelId.toString(),
+  taggingId: taggingId || position.tagId.toString(),
+  localPos: position.tagPoint
+})
+
+const localToService = (position: TaggingPosition, update = false): PartialProps<ServicePosition, 'id'> => ({
+  "id": update ? Number(position.id) : undefined,
+  "tagId": Number(position.taggingId),
+  "modelId": Number(position.modelId),
+  "tagPoint": position.localPos,
+})
+
+
+export const fetchTaggingPositions = async (taggingId: Tagging['id']) => {
+  const positions = await axios.post<ServicePosition[]>(`${TAGGING_POINT_LIST}${taggingId}`, {})
+  return positions.map(position => serviceToLocal(position, taggingId))
+}
+
+export const postAddTaggingPosition = async (position: TaggingPosition) => {
+  const servicePosition = await axios.post<ServicePosition>(INSERT_TAGGING_POINT, localToService(position))
+  return serviceToLocal(servicePosition)
+}
+
+export const postUpdateTaggingPosition = (position: TaggingPosition) => {
+  return axios.post<undefined>(UPDATE_TAGGING_POINT, localToService(position, true))
+}
+  
+export const postDeleteTaggingPosition = (position: TaggingPosition) => {
+  return axios.post<undefined>(DELETE_TAGGING_POINT, { ids: [position.id] })
+}
+
+  

+ 13 - 3
src/api/tagging-style.ts

@@ -1,5 +1,6 @@
 import axios from './instance'
-import { TAGGING_STYLE_LIST } from './constant'
+import { TAGGING_LIST } from './constant'
+import { fetchTaggings } from './tagging'
 
 export interface TaggingStyle {
   id: string
@@ -10,5 +11,14 @@ export interface TaggingStyle {
 
 export type TaggingStyles = TaggingStyle[]
 
-export const getTaggingStyles = () => 
-  axios.post<TaggingStyles>(TAGGING_STYLE_LIST)
+export const getTaggingStyles = async () => {
+  // axios.post<TaggingStyles>(TAGGING_LIST)
+  return [
+    {
+      id: '1', 
+      icon: 'static/img_default/lQLPDhrvVzvNvTswMLAOU-UNqYnnZQG1YPJUwLwA_48_48.png',
+      name: '111',
+      default: true
+    }
+  ]
+}

+ 50 - 55
src/api/tagging.ts

@@ -1,4 +1,5 @@
 import axios from './instance'
+import { params } from '@/env'
 import { 
   TAGGING_LIST,
   DELETE_TAGGING,
@@ -7,84 +8,78 @@ import {
 } from './constant'
 
 import type { Model } from './model'
+import type { TaggingPosition } from './tagging-position'
+import type { TaggingStyle } from './tagging-style'
 
-export interface TaggingPosition {
-  modelId: Model['id']
-  localPos: SceneLocalPos
+interface ServerTagging {
+  "hotIconId": number,
+  "hotIconUrl": string,
+  "getMethod": string,
+  "getUser": string,
+  "id": number,
+  "meta": { "name": string, "url": string } [],
+  "remark": string,
+  "tagDescribe": string,
+  "tagTitle": string,
 }
+
 export interface Tagging {
   id: string
-  styleId: string
+  styleId: TaggingStyle['id']
   title: string,
   desc: string
   part: string
   method: string
   principal: string
   images: string[],
-  positions: TaggingPosition[]
 }
 
+
 export type Taggings = Tagging[]
 
-export const fetchTaggings = async () => {
-  // axios.post<Taggings>(TAGGING_LIST)
-  return [
-    {
-      id: '1231',
-      title: 'aaaa',
-      styleId: '1231',
-      desc: '123123',
-      modelId: '123',
-      part: '123asd',
-      method: '123123a',
-      principal: 'asdasd',
-      images: [
-        'https://gw.alicdn.com/tps/TB1W_X6OXXXXXcZXVXXXXXXXXXX-400-400.png',
-        'https://gw.alicdn.com/tps/TB1W_X6OXXXXXcZXVXXXXXXXXXX-400-400.png'
-      ],
-      positions: [
-        { 
-          modelId: '124',
-          localPos: { x: 1, y: 1, z: 1 }
-        }
-      ]
-    },
 
-    {
-      id: '1231a',
-      title: 'aaaa',
-      styleId: '1231',
-      desc: '123123',
-      part: '123asd',
-      method: '123123a',
-      principal: 'asdasd',
-      images: [
-        'https://gw.alicdn.com/tps/TB1W_X6OXXXXXcZXVXXXXXXXXXX-400-400.png',
-        'https://gw.alicdn.com/tps/TB1W_X6OXXXXXcZXVXXXXXXXXXX-400-400.png'
-      ],
-      positions: [{ 
-        modelId: '123',
-        localPos: { x: 1, y: 1, z: 1 }
-      }
-      ]
-    }
-  ]
+const serviceToLocal = (serviceTagging: ServerTagging): Tagging => ({
+  id: serviceTagging.id.toString(),
+  styleId: serviceTagging.hotIconId.toString(),
+  title: serviceTagging.tagTitle,
+  desc: serviceTagging.tagDescribe,
+  part: serviceTagging.remark,
+  method: serviceTagging.getMethod,
+  principal: serviceTagging.getUser,
+  images: serviceTagging.meta.map(({url}) => url),
+})
+
+const localToService = (tagging: Tagging, update = false): PartialProps<ServerTagging, 'id' | 'hotIconUrl'> & { fusionId: number } => ({
+  "hotIconId": Number(tagging.styleId),
+  "fusionId": params.fushId,
+  "getMethod": tagging.method,
+  "getUser": tagging.principal,
+  "hotIconUrl": "static/img_default/lQLPDhrvVzvNvTswMLAOU-UNqYnnZQG1YPJUwLwA_48_48.png",
+  "id": update ? Number(tagging.id) : undefined,
+  "meta": tagging.images.map(((item, i) => ({ "name": item, "url": item }))),
+  "remark": tagging.part,
+  "tagDescribe": tagging.desc,
+  "tagTitle": tagging.title,
+})
+
+
+export const fetchTaggings = async () => {
+  const staggings = await axios.post<ServerTagging[]>(TAGGING_LIST, {})
+  return staggings.map(serviceToLocal)
 }
 
-export const postAddTagging = (tagging: Tagging) => {
-  console.log('add')
-  return axios.post<Tagging>(INSERT_TAGGING, tagging)
+export const postAddTagging = async (tagging: Tagging) => {
+  const stagging = await axios.post<ServerTagging>(INSERT_TAGGING, localToService(tagging))
+  return serviceToLocal(stagging)
 }
 
-export const postUpdateTagging = async (tagging: Tagging) => {
-  console.log('update')
-  // return axios.post<undefined>(UPDATE_TAGGING, tagging)
+export const postUpdateTagging = (tagging: Tagging) => {
+  return axios.post<undefined>(UPDATE_TAGGING, localToService(tagging, true))
 }
   
 
 export const postDeleteTagging = (id: Tagging['id']) => {
-  console.log('delete')
-  return axios.post<undefined>(DELETE_TAGGING)
+  return axios.post<undefined>(DELETE_TAGGING, { ids: [id] })
 }
 
   

+ 9 - 3
src/components/tagging/list.vue

@@ -1,6 +1,6 @@
 <template>
   <template v-if="custom.showTaggings">
-    <template v-for="(pos, index) in tagging.positions" :key="pos.id">
+    <template v-for="(pos, index) in positions" :key="pos.id">
       <Sign 
         v-if="isShowSign(pos.modelId)"
         :tagging="tagging"
@@ -11,15 +11,21 @@
 </template>
 
 <script lang="ts" setup>
+import { computed } from 'vue'
 import Sign from './sign.vue'
-import { Tagging, models, getModelShowVariable, getModel } from '@/store';
+import { Tagging, getModelShowVariable, getModel, getTaggingPositions } from '@/store';
 import { custom } from '@/env'
 
-defineProps<{ tagging: Tagging }>()
+const props = defineProps<{ tagging: Tagging }>()
 
 const isShowSign = (modelId: string) => {
   const model = getModel(modelId)
   return model?.loaded && getModelShowVariable(model).value
 }
 
+const positions = computed(() => {
+  const positions = getTaggingPositions(props.tagging)
+  return positions
+})
+
 </script>

+ 11 - 4
src/components/tagging/sign.vue

@@ -6,7 +6,11 @@
     @mouseenter="isHover = true"
     @mouseleave="isHover = false"
   >
-    <img :src="taggingStyle?.icon" @click="iconClickHandler" />
+    <img 
+      :src="getResource(taggingStyle.icon)" 
+      @click="iconClickHandler" 
+      v-if="taggingStyle" 
+    />
     <div @click.stop>
       <UIBubble
         class="hot-bubble pc" 
@@ -43,12 +47,14 @@ import { computed, ref, watchEffect, watch } from 'vue'
 import UIBubble from 'bill/components/bubble/index.vue'
 import Images from '@/views/tagging/images.vue'
 import Preview, { MediaType } from '../static-preview/index.vue'
-import { Tagging, getTaggingStyle, getModel } from '@/store';
+import { getTaggingStyle, getModel } from '@/store';
 import { getFileUrl } from '@/utils'
 import { sdk } from '@/sdk'
-import { custom } from '@/env'
+import { custom, getResource } from '@/env'
 
-export type SignProps = { tagging: Tagging, scenePos: Tagging['positions'][number], show?: boolean }
+import type { Tagging, TaggingPosition } from '@/store';
+
+export type SignProps = { tagging: Tagging, scenePos: TaggingPosition, show?: boolean }
 
 
 const props = defineProps<SignProps>()
@@ -71,6 +77,7 @@ model && watch(model, updatePosStyle, { deep: true })
 
 
 const showContent = computed(() => {
+  console.error(!~pullIndex.value , (isHover.value || custom.showTaggingPositions.has(props.scenePos)))
   return !~pullIndex.value 
     && (isHover.value || custom.showTaggingPositions.has(props.scenePos))
 })

+ 13 - 3
src/env/index.ts

@@ -12,7 +12,7 @@ export const showRightCtrlPanoStack = stackFactory(ref<boolean>(true))
 export const showTaggingsStack = stackFactory(ref<boolean>(true))
 export const currentModelStack = stackFactory(ref<Model | null>(null))
 export const showModelsMapStack = stackFactory(ref<Map<Model, boolean>>(new Map))
-export const showModelsChangeStoreStack = stackFactory(ref<boolean>(false))
+export const modelsChangeStoreStack = stackFactory(ref<boolean>(false))
 export const showTaggingPositionsStack = stackFactory(ref<WeakSet<TaggingPosition>>(new WeakSet()))
 // export const showModelsChangeStoreStack = stackFactory
 
@@ -26,14 +26,24 @@ export const custom = flatStacksValue({
   showTaggings: showTaggingsStack,
   currentModel: currentModelStack,
   showModelsMap: showModelsMapStack,
-  showModelsChangeStore: showModelsChangeStoreStack,
+  modelsChangeStore: modelsChangeStoreStack,
   showTaggingPositions: showTaggingPositionsStack
 })
 
 
-export const params = strToParams(location.search) as Params
+export const params = strToParams(location.search) as unknown as Params
+params.fushId = Number(params.fushId)
 export type Params = { 
   m: string,
   id: string,
+  fushId: number,
   token?: string
+}
+
+
+export const getResource = (uri: string) => {
+  if (~uri.indexOf('base64') || ~uri.indexOf('bolb') || ~uri.indexOf('//')) return uri
+  // const url = new URL(uri, '/api')
+  // return url.href
+  return `/api/profile/${uri}`
 }

+ 11 - 5
src/layout/model-list/sign.vue

@@ -3,18 +3,24 @@
     <p>{{ model.title }}</p>
     <div class="model-action" @click.stop>
       <ui-input type="checkbox" v-model="show" />
-      <ui-icon type="del" ctrl @click="$emit('delete')" />
+      <ui-icon 
+        type="del" 
+        ctrl 
+        @click="$emit('delete')" 
+        v-if="model.type !== ModelType.SWSS && custom.modelsChangeStore" 
+      />
     </div>
   </div>
   <div class="model-desc">
-    <p><span>数据来源:</span>四维看看</p>
-    <p><span>数据大小:</span>222MB</p>
-    <p><span>拍摄时间:</span>2022-5-1</p>
+    <p><span>数据来源:</span>{{ ModelTypeDesc[model.type] }}</p>
+    <p><span>数据大小:</span>{{ model.size }}</p>
+    <p><span>拍摄时间:</span>{{ model.time }}</p>
   </div>
 </template>
 
 <script lang="ts" setup>
-import { getModelShowVariable } from '@/store'
+import { getModelShowVariable, ModelTypeDesc, ModelType } from '@/store'
+import { custom } from '@/env'
 
 import type { Model } from '@/store'
 

+ 9 - 2
src/sdk/association.ts

@@ -1,7 +1,7 @@
 import { sdk } from './sdk'
 import { models, taggings, isEdit, sysBus, getModelShowVariable } from '@/store'
 import { toRaw, watchEffect, ref, watch } from 'vue'
-import { viewModeStack, custom } from '@/env'
+import { viewModeStack, custom, getResource } from '@/env'
 import { 
   mount, 
   diffArrayChange, 
@@ -27,7 +27,10 @@ const associationModels = (sdk: SDK) => {
       }
 
       const itemRaw = toRaw(item)
-      const sceneModel = sdk.addModel(itemRaw)
+      const sceneModel = sdk.addModel({
+        ...itemRaw,
+        url: getResource(item.url)
+      })
       sceneModelMap.set(itemRaw, sceneModel)
 
       sceneModel.bus.on('transformChanged', transform => {
@@ -41,6 +44,10 @@ const associationModels = (sdk: SDK) => {
         }
       })
       sceneModel.bus.on('loadDone', () => item.loaded = true)
+      sceneModel.bus.on('loadError', () => {
+        console.error(item, '加载失败')
+        item.error = true
+      })
       sceneModel.bus.on('loadProgress', progress => item.progress = progress)
     }
     for (const item of deleted) {

+ 27 - 6
src/sdk/cover/index.js

@@ -119,7 +119,7 @@ export const enter = (dom) => {
             
             if(o.distance){
                 let position = o.target || o.position
-                return viewer.focusOnObject({ position, distance:o.distance }, 'tag').promise
+                return viewer.focusOnObject({ position}, 'tag', null,{distance:o.distance} ).promise
             }
             let deferred = $.Deferred()
             
@@ -301,6 +301,19 @@ export const enter = (dom) => {
             
         },
         
+        //[path1, paht2], {  time, speed }   
+        calcPathInfo(paths, info){ //传入的time, speed仅有一个。返回完整的 time, speed
+             //这一版的control似乎无法在某个位置上改变角度,位置和角度一般都是一起变的,所以先不增加单位更换功能。
+             
+             let dis = paths[0].position.distanceTo(paths[1])
+             if(info.time != void 0){
+                  info.speed = dis / info.time
+             }else{
+                  info.time = dis / info.speed
+             }
+             return info
+        },
+        
         
         addModel(props){ 
             let bus = mitt()  
@@ -331,10 +344,18 @@ export const enter = (dom) => {
             let progressFun = (progress)=>{
                 bus.emit('loadProgress',progress)
             }
+            
+            let onError = function ( xhr ) {
+                bus.emit('loadError', xhr)
+                console.log('loadError!!!!!!!!!',  props.url)
+            }
+            
             if(props.type == "glb"){////////////////////////////test
-                props.url = '/lib/potree/resources/models/glb/coffeemat.glb'  
+                if(props.url.includes('coffeemat')){
+                    props.url = '/lib/potree/resources/models/glb/coffeemat.glb'  
+                }
             }
-            Potree.addModel(props,  done , progressFun)
+            Potree.addModel(props,  done , progressFun, onError)
             
             let result = {  
                 bus,
@@ -395,9 +416,9 @@ export const enter = (dom) => {
             } 
             
             return result
-        } 
-            
-    
+        }, 
+        
+        
         
     }
    

+ 1 - 0
src/sdk/sdk.ts

@@ -11,6 +11,7 @@ export type SceneModel = ToChangeAPI<Omit<SceneModelAttrs, 'position' | 'rotatio
     bus: Emitter<
       Pick<SceneModelAttrs, 'select'> & 
       { 
+        loadError: void,
         loadDone: void, 
         loadProgress: number,
         changeSelect: boolean,

+ 4 - 3
src/store/index.ts

@@ -1,7 +1,7 @@
 import { ref } from 'vue'
 import { initialModels } from './model'
 import { initialTaggings } from './tagging'
-import { initialTaggingStyles } from './taging-style'
+import { initialTaggingStyles } from './tagging-style'
 import { initialGuides } from './guide'
 
 export const loaded = ref(false)
@@ -25,5 +25,6 @@ export const initialStore = async () => {
 export * from './sys'
 export * from './model'
 export * from './tagging'
-export * from './taging-style'
-export * from './guide'
+export * from './tagging-style'
+export * from './guide'
+export * from './tagging-positions'

+ 5 - 4
src/store/model.ts

@@ -18,7 +18,7 @@ import {
 
 import type { Model as SModel } from '@/api'
 
-export type Model = SModel & { loaded: boolean, progress: number }
+export type Model = SModel & { loaded: boolean, error: boolean, progress: number }
 export type Models = Model[]
 
 export const models = ref<Models>([])
@@ -26,11 +26,11 @@ export const models = ref<Models>([])
 export const getModel = (modelId: Model['id']) => models.value.find(model => model.id === modelId)
 export const getModelShowVariable = (model: Model) => 
   computed({
-    get: () => custom.showModelsChangeStore 
+    get: () => custom.modelsChangeStore 
       ? model.show 
       : custom.showModelsMap.get(model) || false,
     set: (show: boolean) => {
-      if (custom.showModelsChangeStore) {
+      if (custom.modelsChangeStore) {
         model.show = show
       } else {
         custom.showModelsMap.set(model, show)
@@ -40,7 +40,7 @@ export const getModelShowVariable = (model: Model) =>
   
 export const modelsLoaded = ref(false)
 watchPostEffect(() => {
-  modelsLoaded.value = models.value.every(model => model.loaded === true)
+  modelsLoaded.value = models.value.every(model => model.loaded || model.error)
 })
 
 let bcModels: Models = []
@@ -55,6 +55,7 @@ export const backupModels = () => {
 
 const serviceToLocal = (model: SModel): Model => ({
   ...model, 
+  error: false,
   loaded: false, 
   progress: 0,
 })

+ 66 - 0
src/store/tagging-positions.ts

@@ -0,0 +1,66 @@
+import { ref } from 'vue'
+import { autoSetModeCallback, createTemploraryID } from './sys'
+import { 
+  fetchTaggingPositions, 
+  postAddTaggingPosition,
+  postDeleteTaggingPosition,
+  postUpdateTaggingPosition,
+} from '@/api'
+import { 
+  deleteStoreItem, 
+  addStoreItem, 
+  updateStoreItem, 
+  saveStoreItems,
+  recoverStoreItems
+} from '@/utils'
+
+import type { TaggingPosition, TaggingPositions } from '@/api'
+import type { Tagging } from './tagging'
+
+export type { TaggingPosition, TaggingPositions }
+
+export const taggingPositions = ref<TaggingPositions>([])
+export const createTaggingPosition = (position: Partial<TaggingPosition> = {}): TaggingPosition => ({
+  id: createTemploraryID(),
+  taggingId: '',
+  modelId: '',
+  localPos: { x: 0, y: 0, z: 0 },
+  ...position
+})
+
+export const getTaggingPositions = (tagging: Tagging) => 
+  taggingPositions.value.filter(position => position.taggingId === tagging.id) || []
+
+let bcPositions: TaggingPositions = []
+export const getBackupTaggingPositions = () => bcPositions
+export const backupTaggingPositions = () => {
+  bcPositions = taggingPositions.value.map(position => ({
+    ...position,
+    localPos: { ...position.localPos },
+  }))
+}
+
+export const initTaggingPositionsByTagging = async (tagging: Tagging) => {
+  const positions = await fetchTaggingPositions(tagging.id)
+  taggingPositions.value.push(...positions)
+  backupTaggingPositions()
+}
+
+export const recoverTaggingPositions = recoverStoreItems(taggingPositions, getBackupTaggingPositions)
+export const addTaggingPosition = addStoreItem(taggingPositions, postAddTaggingPosition)
+export const updateTaggingPosition = updateStoreItem(taggingPositions, postUpdateTaggingPosition)
+export const deleteTaggingPosition = deleteStoreItem(taggingPositions, postDeleteTaggingPosition)
+export const saveTaggingPositions = saveStoreItems(
+  taggingPositions, 
+  getBackupTaggingPositions,
+  {
+    add: addTaggingPosition,
+    update: updateTaggingPosition,
+    delete: deleteTaggingPosition,
+  }
+)
+export const autoSaveTaggingPositions = autoSetModeCallback(taggingPositions, {
+  backup: backupTaggingPositions,
+  recovery: recoverTaggingPositions,
+  save: saveTaggingPositions,
+})

+ 3 - 10
src/store/taging-style.ts

@@ -1,23 +1,16 @@
-import { ref } from 'vue'
+import { ref, computed } from 'vue'
 import { getTaggingStyles } from '@/api'
 
 import type { TaggingStyles, TaggingStyle } from '@/api'
 
 export const taggingStyles = ref<TaggingStyles>([])
+export const defaultStyle = computed(() => taggingStyles.value.find(style => style.default))
 
 export const getTaggingStyle = (id: TaggingStyle['id']) => 
   taggingStyles.value.find(style => style.id === id)
 
 export const initialTaggingStyles = async () => {
-  // taggings.value = await getTaggingStyles()
-  taggingStyles.value = [
-    {
-      id: '1231',
-      name: 'aaa',
-      icon: 'https://gw.alicdn.com/tps/TB1W_X6OXXXXXcZXVXXXXXXXXXX-400-400.png',
-      default: true
-    }
-  ]
+  taggingStyles.value = await getTaggingStyles()
 }
 
 

+ 32 - 10
src/store/tagging.ts

@@ -1,5 +1,15 @@
 import { ref } from 'vue'
+import { togetherCallback } from '@/utils'
 import { autoSetModeCallback, createTemploraryID } from './sys'
+import { defaultStyle } from './tagging-style'
+import { 
+  initTaggingPositionsByTagging, 
+  saveTaggingPositions,
+  recoverTaggingPositions,
+  backupTaggingPositions,
+  taggingPositions,
+  getTaggingPositions
+} from './tagging-positions'
 import { 
   fetchTaggings, 
   postAddTagging,
@@ -21,20 +31,18 @@ import type { Tagging as STagging } from '@/api'
 
 export type Tagging = LocalMode<STagging, 'images'>
 export type Taggings = Tagging[]
-export type { TaggingPosition } from '@/api'
 
 export const taggings = ref<Taggings>([])
 
 export const createTagging = (tagging: Partial<Tagging> = {}): Tagging => ({
   id: createTemploraryID(),
   title: ``,
-  styleId: '',
+  styleId: defaultStyle.value?.id || '',
   desc: '',
   part: '',
   method: '',
   principal: '',
   images: [],
-  positions: [],
   ...tagging
 })
 
@@ -45,7 +53,6 @@ export const backupTaggings = () => {
   bcTaggings = taggings.value.map(tagging => ({
     ...tagging,
     images: [...tagging.images],
-    positions: [...tagging.positions]
   }))
 }
 
@@ -60,10 +67,21 @@ export const transformTagging = async (tagging: Tagging): Promise<STagging> => {
 }
 
 export const recoverTaggings = recoverStoreItems(taggings, () => bcTaggings)
-export const addTagging = addStoreItem(taggings, postAddTagging, transformTagging)
+export const addTagging = addStoreItem(taggings, async (localTagging) => {
+  const serviceTagging = await postAddTagging(localTagging)
+  const positions = getTaggingPositions(localTagging)
+  for (const position of positions) {
+    position.taggingId = serviceTagging.id
+  }
+  return serviceTagging
+}, transformTagging)
 export const updateTagging = updateStoreItem(taggings, postUpdateTagging, transformTagging)
 export const deleteTagging = deleteStoreItem(taggings, tagging => postDeleteTagging(tagging.id))
-export const initialTaggings = fetchStoreItems(taggings, fetchTaggings, backupTaggings)
+export const initialTaggings = fetchStoreItems(taggings, async () => {
+  const taggings = await fetchTaggings()
+  await Promise.all(taggings.map(initTaggingPositionsByTagging))
+  return taggings
+}, backupTaggings)
 export const saveTaggings = saveStoreItems(
   taggings, 
   getBackupTaggings,
@@ -73,8 +91,12 @@ export const saveTaggings = saveStoreItems(
     delete: deleteTagging,
   }
 )
-export const autoSaveTaggings = autoSetModeCallback(taggings, {
-  backup: backupTaggings,
-  recovery: recoverTaggings,
-  save: saveTaggings,
+
+export const autoSaveTaggings = autoSetModeCallback([taggings, taggingPositions], {
+  backup: togetherCallback([backupTaggings, backupTaggingPositions]),
+  recovery: togetherCallback([recoverTaggings, recoverTaggingPositions]),
+  save: async () => {
+    await saveTaggings()
+    await saveTaggingPositions()
+  },
 })

+ 2 - 2
src/views/merge/index.vue

@@ -33,7 +33,7 @@ import { togetherCallback } from '@/utils'
 import Actions from '@/components/actions/index.vue'
 import { getSceneModel } from '@/sdk'
 import { useViewStack } from '@/hook'
-import { showLeftCtrlPanoStack, showLeftPanoStack, showModelsChangeStoreStack, custom } from '@/env'
+import { showLeftCtrlPanoStack, showLeftPanoStack, custom, modelsChangeStoreStack } from '@/env'
 import { ref } from 'vue'
 
 import type { ActionsProps } from '@/components/actions/index.vue'
@@ -66,7 +66,7 @@ const actionItems: ActionsProps['items'] = [
 useViewStack(() => togetherCallback([
   showLeftCtrlPanoStack.push(ref(false)),
   showLeftPanoStack.push(ref(true)),
-  showModelsChangeStoreStack.push(ref(true))
+  modelsChangeStoreStack.push(ref(true))
 ]))
 useViewStack(autoSaveModels)
 

+ 12 - 4
src/views/tagging/index.vue

@@ -62,7 +62,10 @@ import {
   enterEdit, 
   Model,
   getModel,
-getModelShowVariable
+  getModelShowVariable,
+  getTaggingPositions,
+  taggingPositions,
+createTaggingPosition
 } from '@/store'
 import { 
   custom, 
@@ -93,15 +96,16 @@ const deleteTagging = (tagging: Tagging) => {
 
 let stopFlyTaggingPositions: () => void
 const flyTaggingPositions = (tagging: Tagging) => {
+  const positions = getTaggingPositions(tagging)
   stopFlyTaggingPositions && stopFlyTaggingPositions()
 
   let isStop = false
 
   const flyIndex = (i: number) => {
-    if (isStop || i >= tagging.positions.length) {
+    if (isStop || i >= positions.length) {
       return;
     }
-    const position = tagging.positions[i]
+    const position = positions[i]
     const model = getModel(position.modelId)
     if (!model || !getModelShowVariable(model).value) {
       flyIndex(i + 1)
@@ -169,7 +173,11 @@ watch(selectTagging, (a, b, onCleanup) => {
       if (!position) {
         Message.error('当前位置无法添加')
       } else if (selectTagging.value) {
-        selectTagging.value.positions.push(position)
+        const storePosition = createTaggingPosition({
+          ...position,
+          taggingId: selectTagging.value.id
+        })
+        taggingPositions.value.push(storePosition)
         leave()
       }
     }

+ 8 - 6
src/views/tagging/sign.vue

@@ -1,10 +1,10 @@
 <template>
   <ui-group-option class="sign-tagging" :class="{active: selected}" @click="emit('select')">
     <div class="info">
-      <img :src="getFileUrl(tagging.images[0])">
+      <img :src="getResource(getFileUrl(style.icon))" v-if="style">
       <div>
         <p>{{ tagging.title }}</p>
-        <a @click.stop="$emit('flyPositions')">放置:{{ tagging.positions.length }}</a>
+        <a @click.stop="$emit('flyPositions')">放置:{{ positions.length }}</a>
       </div>
     </div>
     <div class="actions" @click.stop>
@@ -19,12 +19,14 @@
 </template>
 
 <script setup lang="ts">
-import { Tagging } from '@/store'
-import { getFileUrl, asyncTimeout } from '@/utils'
-import { sdk } from '@/sdk'
-
+import { Tagging, getTaggingStyle, getTaggingPositions } from '@/store'
+import { getFileUrl } from '@/utils'
+import { computed } from 'vue';
+import { getResource } from '@/env'
 
 const props = defineProps<{ tagging: Tagging, selected?: boolean }>()
+const style = computed(() => getTaggingStyle(props.tagging.styleId))
+const positions = computed(() => getTaggingPositions(props.tagging))
 
 const emit = defineEmits<{ 
   (e: 'delete'): void 

+ 0 - 1
src/views/tagging/style.scss

@@ -28,7 +28,6 @@
       object-fit: cover;
       border-radius: 4px;
       overflow: hidden;
-      background-color: rgba(255,255,255,.6);
       display: block;
     }
 

+ 3 - 0
vite.config.ts

@@ -32,6 +32,9 @@ export default defineConfig({
     host: '0.0.0.0',
     port: 5173,
     open: true,
+    watch: {
+      usePolling: true
+    },
     proxy: {
       '/api': {
         target: 'http://192.168.0.152:8088/',