root 2 anni fa
parent
commit
a2a28b38d9

+ 160 - 154
public/static/lib/potree/potree.js

@@ -53134,7 +53134,7 @@
 	    funcs: [],
 	    counter: 0,
 	    uniqueID: 0,
-	    start: function(func, duration, done, delay, ease, name, id, cancelFun, ignoreFirstFrame=true) {
+	    start: function(func, duration, done, delay, ease, name, id, cancelFun, ignoreFirstFrame=true, forbitCancel) {
 	        return delay = delay || 0,
 	        this.funcs.push({
 	            func: func,
@@ -53151,6 +53151,7 @@
 				cancelFun : cancelFun,   //取消时执行的函数
 	            updateCount:0,
 	            ignoreFirstFrame,
+	            forbitCancel,
 	        }),
 	        func(0, 16),
 	        this.counter += 1,
@@ -53250,7 +53251,7 @@
 	        var t = void 0 === e ? 0 : e;
 			let cancels = [];
 	        this.funcs = this.funcs.filter(function(e) {
-				var is = e.id == t;
+				var is = e.id == t && !e.forbitCancel;
 				
 				if(is && dealCancelFun){
 	                e.cancelFun && cancels.push(e.cancelFun);
@@ -54069,6 +54070,11 @@
 	    setView( info = {}){
 	        // position, target, duration = 0, callback = null, onUpdate = null, Easing='', cancelFun
 	        this.cancelFlying();
+	        if(this.isFlying()){
+	            if(info.cancelFun)info.cancelFun();
+	            return ;//取消失败
+	        }
+	        
 	        let posWaitDone,  rotWaitDone , dir;
 	        
 	        let posDone = ()=>{
@@ -54160,7 +54166,7 @@
 	                    } 
 	                    posWaitDone = false; 
 	                    info.cancelFun && info.cancelFun();
-	                }, info.ignoreFirstFrame);  
+	                }, info.ignoreFirstFrame,info.forbitCancel);  
 	            } 
 	            
 	            if(endQuaternion || endYaw != void 0){
@@ -54182,26 +54188,13 @@
 	                    //中途取消
 	                    rotWaitDone = false;
 	                    info.cancelFun && info.cancelFun();
-	                }, info.ignoreFirstFrame); 
+	                }, info.ignoreFirstFrame, info.forbitCancel); 
 	                  
 	            }      
 	         
 	            
 	            
-	           /*  transitions.start(lerp.vector(this.position, endPosition, (pos, progress)=>{
-					let t = progress 
-	 
-	                if(endQuaternion){  
-	                    let quaternion = (new THREE.Quaternion()).copy(startQuaternion) 
-	                    lerp.quaternion(quaternion, endQuaternion)(progress),
-	                    this.rotation = new THREE.Euler().setFromQuaternion(quaternion)
-	                }
-	                this.restrictPos()
-	                //console.log('setView flying')             
-	 
-	                info.onUpdate && info.onUpdate(t)//add
-	            }), info.duration, done, 0, info.Easing ? easing[info.Easing] : easing.easeInOutSine  ,null, this.LookTransition, info.cancelFun); //easeInOutQuad
-	            */
+	           
 
 	        } 
 
@@ -54322,17 +54315,17 @@
 	        };
 	        
 	        let callback = info.callback;
-	        info.callback = ()=>{ 
+	        info.callback = info.cancelFun = ()=>{ 
 	            viewport.camera = info.endCamera;  
 	            viewer.scene.measurements.forEach((e)=>{ 
 	                Potree.Utils.updateVisible(e, 'tranCamera', true); 
 	            }); 
 	            viewer.dispatchEvent({type:'camera_changed', viewport:viewer.mainViewport, changeInfo:{}});//update sprite
-	       
+	            
 	            
 	            callback && callback();
 	        }; 
-	        
+	        info.forbitCancel = true; 
 	        
 	        viewer.scene.measurements.forEach((e)=>{
 	            Potree.Utils.updateVisible(e, 'tranCamera', false); //含sprite且实时更新size的都要隐藏
@@ -71278,6 +71271,7 @@ void main()
 			this.textColor = options.textColor || {r: 0, g: 0, b: 0, a: 1.0};
 	        this.borderColor = options.borderColor || { r: 0, g: 0, b: 0, a: 0.0 };
 			this.borderRadius = options.borderRadius || 6;
+	        this.margin = options.margin;
 	        if(options.text != void 0)this.setText(options.text);
 	        this.name = options.name; 
 	         
@@ -71333,21 +71327,29 @@ void main()
 	        //context["font-weight"] = 100; //语法与 CSS font 属性相同。
 			// get size data (height depends only on font size)
 	        
-	        //this.text = '啊啊啊啊啊啊fag'
+	        //this.text = 'f 啊啊啊 jg'
 	        
 			let metrics = context.measureText(this.text );
 			let textWidth = metrics.width;
-			let margin = new Vector2(this.fontsize, Math.max(  this.fontsize*0.4, 10)  );
+			let margin = this.margin || new Vector2(this.fontsize, Math.max(  this.fontsize*0.4, 10)  );
 			let spriteWidth = 2 * margin.x + textWidth + 2 * this.rectBorderThick;
 			let spriteHeight = 2 * margin.y + this.fontsize + 2 * this.rectBorderThick; 
 			context.canvas.width = spriteWidth;
 			context.canvas.height = spriteHeight;
 			context.font = this.fontWeight + ' ' + this.fontsize + 'px ' + this.fontface; 
 
+	 
+	        let expand = Math.max(1, Math.pow(this.fontsize / 16, 1.3)); // 针对英文大部分在baseLine之上所以降低一点,或者可以识别当不包含jgqp时才加这个值  
 	         
-	        let diff = 2;//针对英文大部分在baseLine之上所以降低一点(metrics.fontBoundingBoxAscent - metrics.fontBoundingBoxDescent) / 2
-
-	        context.textBaseline = "middle";
+	        //canvas原点在左上角
+	        context.textBaseline = 'alphabetic'; //  "middle"  //设置文字基线。当起点y设置为0时,只有该线以下的部分被绘制出来。middle时文字显示一半(但是对该字体所有字的一半,有的字是不一定显示一半的,尤其汉字),alphabetic时是英文字母的那条基线。
+	        
+	        let actualHeight = metrics.actualBoundingBoxAscent + metrics.actualBoundingBoxDescent; // 当前文本字符串在这个字体下用的实际高度
+	        
+	        //文字y向距离从textBaseline向上算
+	        let y = metrics.actualBoundingBoxAscent + margin.y + expand; 
+	        //console.log(this.text, 'y' , y, 'actualBoundingBoxAscent', metrics.actualBoundingBoxAscent,'expand',expand )
+	        
 	        
 	        // border color
 	        context.strokeStyle = 'rgba(' + this.borderColor.r + ',' + this.borderColor.g + ',' +
@@ -71365,12 +71367,12 @@ void main()
 	            context.strokeStyle = 'rgba(' + this.textBorderColor.r + ',' + this.textBorderColor.g + ',' +
 	                this.textBorderColor.b + ',' + this.textBorderColor.a + ')';
 	            context.lineWidth = this.textBorderThick;
-	            context.strokeText(this.text , this.rectBorderThick + margin.x,spriteHeight/2  + diff );
+	            context.strokeText(this.text , this.rectBorderThick + margin.x, y /* spriteHeight/2  + expand */ );
 	        }
 	        
 			context.fillStyle = 'rgba(' + this.textColor.r + ',' + this.textColor.g + ',' +
 				this.textColor.b + ',' + this.textColor.a + ')';
-			context.fillText(this.text , this.rectBorderThick + margin.x, spriteHeight/2  + diff );//x,y
+			context.fillText(this.text , this.rectBorderThick + margin.x, y  /* spriteHeight/2  + expand  */);//x,y
 
 			let texture = new Texture(canvas);
 			texture.minFilter = LinearFilter;
@@ -73613,10 +73615,8 @@ void main()
 	                type: 'isVisible',
 	                visible: shouldVisi,
 	                reason,
-	            }); 
-	        }
-	        
-	        
+	            });  
+	        } 
 	    };    
 	    
 	    
@@ -73651,10 +73651,12 @@ void main()
 	    update(); 
 	    
 	}; 
-	 
-	 
-	 
-	 
+	/* 
+	    复杂案例: 如果物体默认隐藏, 当符合任何一个其他条件时可见,则可:
+	    Potree.Utils.updateVisible(this, "default", false, 0 ) //默认隐藏    
+	    Potree.Utils.updateVisible(this, 条件名,  ifShow, 1, ifShow?'add':'cancel' ) //其他的条件
+	*/ 
+
 	Utils.getObjVisiByReason = function(object,reason){//获取在某条件下是否可见.  注: 用户在数据集选择可不可见为"datasetSelection"
 	    if(object.visible)return true
 	    else {
@@ -75273,7 +75275,7 @@ void main()
 	        color:'#00C8AF',
 	        default:{
 	            color:"#2F8FFF",//"#00c7b2",
-	            opacity:0.7
+	            opacity:0.8
 	        },
 	        highlight:{
 	            color:"#2F8FFF",//"#00c7b2",
@@ -75286,7 +75288,7 @@ void main()
 	        ,   
 	        backColor:'#333333',
 	         
-	        lineWidth: 4,
+	        lineWidth: 3,
 	       
 	        textColor: "#FFFFFF"
 	        
@@ -81734,18 +81736,21 @@ void main()
 	const markerSizeInfo = {
 	    minSize : 25 ,  maxSize : 65,   nearBound : 0.2, farBound : 4,
 	};
-	const labelSizeInfo = {width2d:200};
+	const labelSizeInfo = {width2d:190};
 	const mainLabelProp = { 
 	    backgroundColor: {r: defaultColor$1.r*255, g: defaultColor$1.g*255, b: defaultColor$1.b*255, a:config$1.measure.default.opacity},
 	    textColor: {r: textColor.r*255, g: textColor.g*255, b: textColor.b*255, a: 1.0},
-	    fontsize:16, 
-	    useDepth : true ,
+	    fontsize: 14, 
+	    useDepth : true , borderRadius : 12, margin:{x:20,y:4},
 	    renderOrder : 5, pickOrder:5, 
 	};
+	  
+	 
+
 	const subLabelProp = { 
-	    backgroundColor: {r: 255, g: 255, b: 255, a:1},
-	    textColor: {r: 0, g: 0, b:0, a: 1.0},
-	    fontsize:14, 
+	    backgroundColor: {r: 255, g: 255, b: 255, a:config$1.measure.default.opacity},
+	    textColor: {r: 0.3, g: 0.3, b:0.3, a: 1.0},
+	    fontsize:12, borderRadius : 12,  margin:{x:20,y:4},
 	    renderOrder : 4, pickOrder:4,
 	};
 
@@ -81929,9 +81934,9 @@ void main()
 	            let center = new Vector3().addVectors(p1,p2).multiplyScalar(0.5);  
 	            label.setPos(center); 
 	            distance = distance == void 0 ? p1.distanceTo(p2) : distance; 
-	            var text = viewer.unitConvert.convert(distance, 'distance', Potree.settings.precision, this.unitSystem, 0.1 , true);//distance要传0.1 这个factor
+	            var text = this.labelText || viewer.unitConvert.convert(distance, 'distance', Potree.settings.precision, this.unitSystem, 0.1 , true);//distance要传0.1 这个factor
 	            label.setText(text);
-	            return distance
+	          
 	        };
 	         
 	         
@@ -81947,10 +81952,10 @@ void main()
 	            let previousPoint = this.points[previousIndex];
 
 	          
-	            if(this.showDistances){ // edge labels
+	            if(this.showDistances || this.labelText){ // edge labels
 	                let edgeLabel = this.edgeLabels[index];
-	                let distance = point.distanceTo(nextPoint);
-	                edgeLabel.shouldVisi = (index < lastIndex || this.isRect || this.closed && !this.isNew ) && distance>0; 
+	                let distance = this.labelText || point.distanceTo(nextPoint);
+	                edgeLabel.shouldVisi = this.labelText || (index < lastIndex || this.isRect || this.closed && !this.isNew ) && distance>0; 
 	                /* this.closed || */edgeLabel.setVisible(edgeLabel.shouldVisi);  
 	                if(edgeLabel.visible){
 	                    setEdgeLabel(edgeLabel,point,nextPoint,distance);
@@ -82108,6 +82113,7 @@ void main()
 	            } 
 	        }
 	        this.isEditing = state;  
+	        viewer.dispatchEvent({type:'MeasureDragChange',state});
 	    }
 	    
 
@@ -82173,8 +82179,8 @@ void main()
 	            //this.closed || this.edgeLabels.forEach(e=>e.elem.addClass('highLight')  )
 	            this.setEdgesDisplay(true, hoverObject=="screenshot");
 	            
-	            this.areaLabel && setLabelHightState(this.areaLabel, true); 
-	            this.closed || this.edgeLabels.forEach(e=>setLabelHightState(e, true)  );
+	            this.areaLabel && this.setLabelHightState(this.areaLabel, true); 
+	            this.closed || this.edgeLabels.forEach(e=>this.setLabelHightState(e, true)  );
 	              
 	        }else {
 	            this.markers.forEach(e=>this.setMarkerSelected(e, 'unhover', 'selectAll' ));
@@ -82183,8 +82189,8 @@ void main()
 	            this.setEdgesDisplay(false, hoverObject=="screenshot");
 	            //this.areaLabel && this.areaLabel.elem.removeClass('highLight')
 	            //this.closed || this.edgeLabels.forEach(e=>e.elem.removeClass('highLight')  )
-	            this.areaLabel && setLabelHightState(this.areaLabel, false); 
-	            this.closed || this.edgeLabels.forEach(e=>setLabelHightState(e, false)  );
+	            this.areaLabel && this.setLabelHightState(this.areaLabel, false); 
+	            this.closed || this.edgeLabels.forEach(e=>this.setLabelHightState(e, false)  );
 	            
 	        }
 	           
@@ -82199,6 +82205,32 @@ void main()
 	        viewer.mapViewer && viewer.mapViewer.dispatchEvent('content_changed');
 	    }
 	    
+	    
+	    
+	    
+	    setLabelHightState(label, state){ 
+	        if(state){  
+	            label.backgroundColor = {r:255, g:255, b:255, a:config$1.measure.highlight.opacity},
+	            //label.backgroundColor.a = config.measure.highlight.opacity
+	            label.sprite.material.useDepth = false;
+	            label.textColor = {r: this.color.r*255, g:  this.color.g*255, b:  this.color.b*255, a: 1}; 
+	        }else {
+	            label.backgroundColor = {r: this.color.r*255, g:  this.color.g*255, b:  this.color.b*255, a:config$1.measure.default.opacity};
+	            //label.backgroundColor.a = config.measure.default.opacity
+	            label.sprite.material.useDepth = true;
+	            label.textColor = {r: 255, g: 255, b: 255, a: 1}; 
+	            
+	        }  
+	        label.updateTexture();  
+	    }
+
+	    
+	    
+	    
+	    
+	    
+	    
+	    
 		removeMarker(index ){  
 	        super.removeMarker(index);
 	        
@@ -82448,7 +82480,7 @@ void main()
 	                transparent: !0,
 	                opacity: 1,
 	                map: texLoader$2.load(Potree.resourcePath+'/textures/pic_point32.png' ), 
-	                useDepth:true ,
+	                //useDepth:true ,
 	                replaceColor:this.color,
 	                beReplacedRed: 0.184,   //0.18431372
 	                mapColorReplace:true
@@ -82469,7 +82501,7 @@ void main()
 	                dashSize: 0.1, 
 	                gapSize: 0.02,
 	                dashed: true,
-	                lineWidth: config$1.measure.lineWidth  
+	                lineWidth: 2 
 	            })      
 	        };
 	    
@@ -82593,7 +82625,12 @@ void main()
 	            prop.maxMarkers = 2,
 	            prop.minMarkers = 2,
 	            prop.faceDirection = "horizontal";  
-	                   
+	        }else if(prop.measureType == "Hor LINE with Text"){ //add 
+	            prop.showEdges = true,
+	            prop.maxMarkers = 2,
+	            prop.minMarkers = 2,
+	            prop.faceDirection = "horizontal";  
+	                 
 	        }else if(prop.measureType == 'Area'){
 	            prop.showDistances = true,  
 	            prop.atPlane = true,                
@@ -82777,37 +82814,6 @@ void main()
 
 
 
-	function setLabelHightState(label, state){
-	    /* if(state){ 
-	        label.backgroundColor =  {r: highlightColor.r*255, g: highlightColor.g*255, b: highlightColor.b*255, a:config.measure.highlight.opacity},
-	        label.backgroundColor.a = config.measure.highlight.opacity
-	        label.sprite.material.useDepth = false;
-	        
-	    }else{
-	        label.backgroundColor = mainLabelProp.backgroundColor
-	        label.backgroundColor.a = config.measure.default.opacity
-	        label.sprite.material.useDepth = true
-	        
-	    }  */
-	    
-	    if(state){  
-	        //label.backgroundColor =  {r: this.color[0]*255, g:  this.color[1]*255, b:  this.color[2]*255, a:config.measure.highlight.opacity},
-	        label.backgroundColor.a = config$1.measure.highlight.opacity;
-	        label.sprite.material.useDepth = false;
-	        
-	    }else {
-	        //label.backgroundColor = {r: this.color[0]*255, g:  this.color[1]*255, b:  this.color[2]*255
-	        label.backgroundColor.a = config$1.measure.default.opacity;
-	        label.sprite.material.useDepth = true;
-	        
-	    } 
-	    
-	    
-	    label.updateTexture(); 
-	    //label.sprite.material.needsUpdate = true 
-	}
-
-
 
 	function createCircleRadiusLabel$1(){
 		const circleRadiusLabel = new TextSprite$2("");
@@ -88599,9 +88605,9 @@ void main()
 	                var width_ = width * view.width;
 	                var height_ = height * view.height;
 	                
+	                view.setResolution(Math.ceil(width_), Math.ceil(height_), width, height ); //本来应该是floor,但是这样奇数时会少一个像素,导致向左移一个像素且宽度少1。现在则多绘制1个像素,超出的1个像素应该不会绘制出来(但不知道其他地方是否有偏差,比如pick时)
 	                if(height_ == 0)return  //avoid NAN
 	                
-	                view.setResolution(Math.ceil(width_), Math.ceil(height_), width, height ); //本来应该是floor,但是这样奇数时会少一个像素,导致向左移一个像素且宽度少1。现在则多绘制1个像素,超出的1个像素应该不会绘制出来(但不知道其他地方是否有偏差,比如pick时)
 	                let aspect = width_ / height_;  //camera的参数精确些,不用视口的归整的resolution像素值,否则hasChange无法为true, 导致canvasResize了但map没update从而闪烁
 	                view.camera.aspect = aspect;
 	                
@@ -89654,7 +89660,7 @@ void main()
 	        
 	        
 	        
-	        let canUseDepthTex = (Potree.settings.displayMode == 'showPanos' || useDepthTex)
+	        let canUseDepthTex = !Potree.settings.unableUseDepTexPick && (Potree.settings.displayMode == 'showPanos' || useDepthTex)
 	            && viewer.images360.currentPano.pointcloud.hasDepthTex && viewport == viewer.mainViewport && !usePointcloud; 
 	        
 	        
@@ -89735,7 +89741,7 @@ void main()
 	        //点云费时:2-15ms
 	        //深度图费时: 0.1-0.2ms
 
-	        
+	        this.viewer.dispatchEvent({type:'getIntersect',  intersect});
 	        
 	        if(onlyGetIntersect){ 
 	            return intersect
@@ -89799,11 +89805,9 @@ void main()
 	        
 	            let dontIntersect =  this.drag && viewport.alignment || isFlying; /* viewer.images360.flying */ // flying 时可能卡顿
 	            //console.log('dontIntersectPointcloud',dontIntersectPointcloud)
-	              
-	            /* if(e.onlyGetIntersect )   */intersect = this.getIntersect(viewport,  e.onlyGetIntersect, e.pickWindowSize, !!dontIntersect, e.whichPointcloud); //数据集多的时候卡顿
-	            /* else  Potree.Common.intervalTool.isWaiting('getIntersect', ()=>{  
-	                 this.intersect = this.getIntersect(viewport,  e.onlyGetIntersect, e.pickWindowSize, !!dontIntersect, e.whichPointcloud) //数据集多的时候卡顿
-	            }, 156); */
+	               
+	            intersect = this.getIntersect(viewport,  e.onlyGetIntersect, e.pickWindowSize, !!dontIntersect, e.whichPointcloud || e.usePointcloud || this.drag); //深度图不准,尽量用点云
+	             
 		                 
 	            //console.log('intersectPoint', intersectPoint)
 	        } 
@@ -91535,41 +91539,34 @@ void main()
 	                
 	                //不过平板无hover事件
 	                faceMesh.addEventListener('mouseover', (e)=>{
-	                    if(navCubeViewer.changingView)return
+	                    if(viewer.mainViewport.view.isFlying())return
 	                    faceMesh.material.uniforms.faceColor.value.set(Colors.blue);
 	                    //console.log('变', name)
 	                    navCubeViewer.dispatchEvent('content_changed');
 	                });
 	                faceMesh.addEventListener('mouseleave', (e)=>{
-	                    if(navCubeViewer.changingView)return
+	                    if(viewer.mainViewport.view.isFlying())return
 	                    faceMesh.material.uniforms.faceColor.value.set(Colors.black);
 	                    //console.log('回', name)
 	                    navCubeViewer.dispatchEvent('content_changed');
 	                });
 	                
 	                faceMesh.addEventListener('click', (e)=>{  
-	                    if(navCubeViewer.switchView('ortho', directions[name] ,   ()=>{ 
-	                        faceMesh.material.uniforms.faceColor.value.set(Colors.black);
+	                    /* if(navCubeViewer.switchView('ortho', directions[name] ,   ()=>{ 
+	                        faceMesh.material.uniforms.faceColor.value.set(Colors.black)
 	                    }) ){
-	                        faceMesh.material.uniforms.faceColor.value.set(Colors.blue); 
-	                    }
-	                }); 
-	                 
-	                if(name == 'Top'){
-	                    navCubeViewer.addEventListener('enterTopView',()=>{ 
-	                        faceMesh.dispatchEvent('click');  
-	                        
-	                    }); 
-	                    navCubeViewer.addEventListener('leaveTopView',()=>{ 
-	                        if(navCubeViewer.lastView){
-	                            navCubeViewer.switchView2(navCubeViewer.lastView); 
-	                        }
-	                    });
+	                        faceMesh.material.uniforms.faceColor.value.set(Colors.blue) 
+	                    } */
 	                    
 	                    
-	                }
-	                 
+	                    if(viewer.mainViewport.view.isFlying())return
+	                    navCubeViewer.switchView('ortho', directions[name] ,   ()=>{ 
+	                        faceMesh.material.uniforms.faceColor.value.set(Colors.black);
+	                    }); 
+	                    faceMesh.material.uniforms.faceColor.value.set(Colors.blue); 
+	                }); 
 	            });
+	            
 	        };  
 	        
 	         
@@ -91692,6 +91689,24 @@ void main()
 	                });
 	                
 	            }); 
+	            
+	            
+	            //外部传消息,使进入俯视 
+	            this.addEventListener('enterTopView',()=>{  
+	                let baseLine = viewer.scene.measurements.find(e=>e.isBaseLine);  //使基准线在俯视图中水平
+	                let yaw = baseLine ? new Vector2().subVectors(baseLine.points[0], baseLine.points[1]).angle() : 0; 
+	                this.switchView('ortho', {dir: new Vector3(0,0,-1),yaw,pitch: -1.5707963267948966}); 
+	            }); 
+	            this.addEventListener('leaveTopView',()=>{ 
+	                if(this.lastView){
+	                    this.switchView2(this.lastView); 
+	                }
+	            });
+	            
+	                
+	                 
+	            
+	            
 	        });
 	        
 	      
@@ -91785,7 +91800,7 @@ void main()
 	        }
 	    } */
 	    switchView(type, {yaw, pitch, dir}={}, done){
-	        if(this.changingView)return
+	        if(viewer.mainViewport.view.isFlying())return
 	        let view = viewer.mainViewport.view;
 	        this.lastView = view.clone();
 	        if(viewer.mainViewport.camera.type == 'OrthographicCamera'){
@@ -91823,11 +91838,11 @@ void main()
 	                endPitch: pitch, endYaw: yaw , dir,  startCamera, endCamera
 	            }).promise.done(()=>{  
 	                //viewer.dispatchEvent('reachTopView')
-	                this.changingView = false;
+	                 
 	                done && done();
 	                navCubeViewer.dispatchEvent('content_changed');
 	            });
-	            this.changingView = true;
+	             
 	        }else {
 	            
 	            if(viewer.mainViewport.camera == viewer.scene.cameraO){
@@ -91853,14 +91868,14 @@ void main()
 	                view.tranCamera(viewer.mainViewport,  { position ,   
 	                    callback:()=>{ 
 	                        done && done();
-	                        this.changingView = false;
+	                         
 	                    }, startCamera:viewer.scene.cameraO, endCamera:viewer.scene.cameraP, midCamera:viewer.scene.cameraBasic
 	                }, 500);
-	                this.changingView = true;
+	                 
 	                
 	            } 
 	        }
-	        return this.changingView
+	         
 	    } 
 	    
 	    
@@ -91868,10 +91883,10 @@ void main()
 	    
 	    
 	    switchView2(viewInfo){ //直接输入view改变
-	        if(this.changingView)return
+	        
 	        let view = viewer.mainViewport.view;
 	        let startCamera, endCamera; 
-	        this.changingView = true;
+	     
 	    
 	        if(viewInfo.isOrtho){
 	            if(viewer.mainViewport.camera != viewer.scene.cameraO){ 
@@ -91883,7 +91898,7 @@ void main()
 	                view.moveOrthoCamera(viewer.mainViewport,  {endPosition:viewInfo.position,
 	                    endPitch: viewInfo.pitch, endYaw: viewInfo.yaw ,  zoom: viewInfo.zoom, 
 	                    callback:()=>{ 
-	                        this.changingView = false;
+	                        
 	                    }, 
 	                }, 500);
 	            }
@@ -91897,7 +91912,7 @@ void main()
 	                    endPitch: viewInfo.pitch, endYaw: viewInfo.yaw ,   
 	                    startCamera,  endCamera,            
 	                    callback:()=>{ 
-	                        this.changingView = false;
+	                       
 	                    }, 
 	                }, 500);
 	            }
@@ -91910,7 +91925,7 @@ void main()
 	                endPitch: viewInfo.pitch, endYaw: viewInfo.yaw ,   
 	                startCamera,   endCamera,   midCamera:viewer.scene.cameraBasic ,            
 	                callback:()=>{ 
-	                    this.changingView = false;
+	                   
 	                }, 
 	            }, 500);
 	        } 
@@ -106040,48 +106055,38 @@ ENDSEC
 	        });
 	        
 	        var updateVisi = (e)=>{
-	            if(e.hoverViewport == viewer.mainViewport){
+	            //if(e.hoverViewport == viewer.mainViewport){
 	                Potree.Utils.updateVisible(this,"atViewport", true);
 	                this.update(e.intersect && e.intersect.location);
-	            }else {
-	                Potree.Utils.updateVisible(this,"atViewport", false); //小地图不显示
-	            } 
+	            /* }else{
+	                Potree.Utils.updateVisible(this,"atViewport", false) //小地图不显示
+	            } */ 
 	            
 	        };
 	        
-	        viewer.addEventListener('global_mousemove', updateVisi);
-	        viewer.addEventListener('global_touchstart', updateVisi);
+	        //viewer.addEventListener('global_mousemove', updateVisi)
+	        viewer.addEventListener('global_touchstart', updateVisi); 
+	        viewer.addEventListener('getIntersect', updateVisi);
 	        
 	        
-	        /* viewer.addEventListener("beginSplitView",()=>{
-	            this.updateVisible("splitView", false) 
-	        })
-	        viewer.addEventListener("finishSplitView",()=>{
-	            this.updateVisible("splitView", true) 
-	        })  */
-	         
+	     
 	         
 	        this.addEventListener("setEnable",(e)=>{
-	            Potree.Utils.updateVisible(this, "enable", e.value); //界面开关
+	            Potree.Utils.updateVisible(this, "enable", e.value, 1,   e.value?'add':'cancel' ); //界面开关
 	            /* if(Potree.settings.displayMode == 'showPanos') && e.value){
 	                Potree.settings.pointDensity = 'magnifier'
 	            }else if() */
 	            
 	        });
-	         
-	         
-	        if(Potree.settings.isOfficial){
-	            Potree.Utils.updateVisible(this, "enable", false); 
-	        }else {
-	            Potree.Utils.updateVisible(this, "measure", false); 
-	            viewer.addEventListener("measureMovePoint",()=>{//测量开始
-	                Potree.Utils.updateVisible(this, "measure", true); 
-	            });
-	            viewer.addEventListener("endMeasureMove",()=>{
-	                Potree.Utils.updateVisible(this, "measure", false); 
-	            });
-	        }
+	          
+	        //默认隐藏, 显示的条件:测量拖拽  或  外部消息setEnable
 	        
+	        Potree.Utils.updateVisible(this, "default", false, 0); //默认隐藏 
+	        
+	        viewer.addEventListener("MeasureDragChange",(e)=>{//测量drag 
+	            Potree.Utils.updateVisible(this, "measure", e.state, 1,   e.state?'add':'cancel'); 
+	        });
+	         
 	        
 	        viewer.scene.view.addEventListener('flyingDone',()=>{
 	            if(!this.visible)return
@@ -106096,11 +106101,12 @@ ENDSEC
 	    
 	    //注意:在鼠标没有移动的时候,无法获取到最新的intersect, 放大镜内的内容可能是错误的。全景模式下更奇怪,原因未知
 	    update(aimPos){//相机靠近 navvis的做法 
+	     
 	        var dontRender = this.dontRender || !(aimPos instanceof Vector3) || Potree.settings.displayMode == 'showPanos' && viewer.images360.flying;
 	        aimPos = aimPos instanceof Vector3 ?  aimPos : this.aimPos;
 	        if(!aimPos  || !this.visible)return
 	        
-	        
+	        //console.log('aimPos', aimPos)
 	        
 	        var playerCamera = viewer.scene.getActiveCamera();
 	        

File diff suppressed because it is too large
+ 1 - 1
public/static/lib/potree/potree.js.map


File diff suppressed because it is too large
+ 1 - 1
server/test/a0k4xu045_202305311600080410/attach/sceneStore


+ 458 - 11
src/graphic/Controls/AddCrossRoad.js

@@ -4,11 +4,167 @@ import { listenLayer } from "../ListenLayer";
 import { roadPointService } from "../Service/RoadPointService";
 import { roadService } from "../Service/RoadService";
 import { edgeService } from "../Service/EdgeService";
+import { dataService } from "../Service/DataService";
+import { uiService } from "../Service/UIService";
+import UIEvents from "../enum/UIEvents.js";
+import Constant from "../Constant.js";
+import Settings from "../Settings.js";
+import RoadTemplate from "../enum/RoadTemplate";
+import { curveRoadPointService } from "../Service/CurveRoadPointService";
+import { curveRoadService } from "../Service/CurveRoadService";
+import { curveEdgeService } from "../Service/CurveEdgeService";
+import CurveRoad from "../Geometry/CurveRoad.js";
 
 export default class AddCrossRoad {
   constructor() {}
 
-  build(position, count) {}
+  build(position) {
+    const roadTemplate = uiService.getSelectRoadTemplate();
+    // 丁字路口
+    if (roadTemplate == RoadTemplate.TJunction) {
+      this.buildThree(position);
+    }
+    // 十字路口
+    else if (roadTemplate == RoadTemplate.Crossroads) {
+      this.buildFour(position);
+    }
+    // 五岔路口
+    else if (roadTemplate == RoadTemplate.FiveForks) {
+      this.buildFive(position);
+    }
+    // 六岔路口
+    else if (roadTemplate == RoadTemplate.SixForkIntersection) {
+      this.buildSix(position);
+    }
+    // s型弯路
+    else if (roadTemplate == RoadTemplate.SBend) {
+      this.buildCurveRoad(position);
+    }
+    // 出口匝道
+    else if (roadTemplate == RoadTemplate.ExitRamp) {
+      this.buildExitRamp(position);
+    }
+    // 国道(路肩)
+    else if (roadTemplate == RoadTemplate.NationalHighwayShoulder) {
+      this.buildNationalHighwayShoulder(position);
+    }
+    // 室内路段
+    else if (roadTemplate == RoadTemplate.IndoorSection) {
+      this.buildIndoorSection(position);
+    }
+    // 弯道
+    else if (roadTemplate == RoadTemplate.Bend) {
+      this.buildBend(position);
+    }
+    // 急转弯道
+    else if (roadTemplate == RoadTemplate.SharpCurve) {
+      this.buildSharpCurve(position);
+    }
+    // 直角弯道
+    else if (roadTemplate == RoadTemplate.Corner) {
+      this.buildCorner(position);
+    }
+    // 进口砸到
+    else if (roadTemplate == RoadTemplate.ImportSmashedRoad) {
+      this.buildImportSmashedRoad(position);
+    }
+    // 高速收费站
+    else if (roadTemplate == RoadTemplate.HighSpeedTollBooth) {
+      this.buildHighSpeedTollBooth(position);
+    }
+    // 高速港湾
+    else if (roadTemplate == RoadTemplate.HighSpeedHarbor) {
+      this.buildHighSpeedHarbor(position);
+    }
+    // 高速路段
+    else if (roadTemplate == RoadTemplate.HighwaySection) {
+      this.buildHighwaySection(position);
+    }
+    // 宽变窄路段
+    else if (roadTemplate == RoadTemplate.WideNarrowRoad) {
+      this.buildWideNarrowRoad(position);
+    }
+  }
+
+  //s型弯路
+  buildCurveRoad(position) {
+    const roadLen = 500;
+    const offsetDis = 100;
+    let startPoint = {
+      x: position.x,
+      y: position.y + roadLen / 2,
+    };
+    let endPoint = {
+      x: position.x,
+      y: position.y - roadLen / 2,
+    };
+    startPoint = curveRoadPointService.create(startPoint);
+    endPoint = curveRoadPointService.create(endPoint);
+
+    let curveRoad = new CurveRoad(startPoint.vectorId, endPoint.vectorId);
+    dataService.addCurveRoad(curveRoad);
+
+    startPoint.setPointParent(curveRoad.vectorId);
+    startPoint.setIndex(0);
+
+    endPoint.setPointParent(curveRoad.vectorId);
+    endPoint.setIndex(2);
+
+    let edgePoints = mathUtil.RectangleVertex(
+      startPoint,
+      endPoint,
+      curveRoad.leftWidth +
+        curveRoad.rightWidth +
+        curveRoad.midDivide.midDivideWidth
+    );
+
+    let leftEdge = curveEdgeService.create(
+      edgePoints.leftEdgeStart,
+      edgePoints.leftEdgeEnd,
+      null,
+      curveRoad.vectorId
+    );
+
+    let rightEdge = curveEdgeService.create(
+      edgePoints.rightEdgeStart,
+      edgePoints.rightEdgeEnd,
+      null,
+      curveRoad.vectorId
+    );
+
+    curveRoad.setLeftEdge(leftEdge.vectorId);
+    curveRoad.setRightEdge(rightEdge.vectorId);
+
+    curveRoad.points.push(startPoint);
+    curveRoad.points.push(endPoint);
+
+    leftEdge.points.push(edgePoints.leftEdgeStart);
+    leftEdge.points.push(edgePoints.leftEdgeEnd);
+
+    rightEdge.points.push(edgePoints.rightEdgeStart);
+    rightEdge.points.push(edgePoints.rightEdgeEnd);
+
+    //得有点曲率
+    const midPoint = {
+      x: (startPoint.x + endPoint.x) / 2,
+      y: (startPoint.y + endPoint.y) / 2,
+    };
+    let mid1 = {
+      x: (startPoint.x + midPoint.x) / 2,
+      y: (startPoint.y + midPoint.y) / 2,
+    };
+    let mid2 = {
+      x: (endPoint.x + midPoint.x) / 2,
+      y: (endPoint.y + midPoint.y) / 2,
+    };
+
+    curveRoadService.addCPoint(curveRoad, mid1, 0);
+    curveRoadService.addCPoint(curveRoad, mid2, 1);
+    mid1.x -= offsetDis;
+    mid2.x += offsetDis;
+    curveRoadService.updateForMovePoint(curveRoad.points[1].vectorId, mid1);
+    curveRoadService.updateForMovePoint(curveRoad.points[2].vectorId, mid2);
+  }
 
   //三岔口
   buildThree(position) {
@@ -25,15 +181,12 @@ export default class AddCrossRoad {
     });
 
     let start3 = roadPointService.create({
-      x: end.x - len,
-      y: end.y,
+      x: end.x,
+      y: end.y - len,
     });
 
     //需要设置公路的车道数,是否双向等等
-    // this.leftDrivewayCount = Settings.roadLeftDrivewayCount;
-    // this.rightDrivewayCount = Settings.roadRightDrivewayCount;
-    // this.singleRoadDrivewayCount = Settings.singleRoadDrivewayCount;
-    // this.way = Settings.wayType;
+    uiService.isBelongRoad(UIEvents.TwoEdgeOneLanRoad);
 
     roadService.create(start1.vectorId, end.vectorId);
     roadService.create(start2.vectorId, end.vectorId);
@@ -66,10 +219,7 @@ export default class AddCrossRoad {
     });
 
     //需要设置公路的车道数,是否双向等等
-    // this.leftDrivewayCount = Settings.roadLeftDrivewayCount;
-    // this.rightDrivewayCount = Settings.roadRightDrivewayCount;
-    // this.singleRoadDrivewayCount = Settings.singleRoadDrivewayCount;
-    // this.way = Settings.wayType;
+    uiService.isBelongRoad(UIEvents.TwoEdgeOneLanRoad);
 
     roadService.create(start1.vectorId, end.vectorId);
     roadService.create(start2.vectorId, end.vectorId);
@@ -95,6 +245,303 @@ export default class AddCrossRoad {
     roadService.create(start5.vectorId, end.vectorId);
     edgeService.updateEdgeForMulRoad(end.vectorId);
   }
+
+  //六岔口
+  buildSix(position) {
+    const len = 300;
+    const points = mathUtil.createSixPoint(position, len);
+    let end = roadPointService.create(position);
+    let start1 = roadPointService.create(points[0]);
+    let start2 = roadPointService.create(points[1]);
+    let start3 = roadPointService.create(points[2]);
+    let start4 = roadPointService.create(points[3]);
+    let start5 = roadPointService.create(points[4]);
+    let start6 = roadPointService.create(points[5]);
+    roadService.create(start1.vectorId, end.vectorId);
+    roadService.create(start2.vectorId, end.vectorId);
+    roadService.create(start3.vectorId, end.vectorId);
+    roadService.create(start4.vectorId, end.vectorId);
+    roadService.create(start5.vectorId, end.vectorId);
+    roadService.create(start6.vectorId, end.vectorId);
+    edgeService.updateEdgeForMulRoad(end.vectorId);
+  }
+
+  buildExitRamp(position) {
+    const roadLen = 600;
+    let startPoint = {
+      x: position.x,
+      y: position.y + (roadLen * 3) / 5,
+    };
+    let endPoint = {
+      x: position.x,
+      y: position.y - (roadLen * 2) / 5,
+    };
+    startPoint = roadPointService.create(startPoint);
+    endPoint = roadPointService.create(endPoint);
+    let crossPoint = roadPointService.create(position);
+
+    uiService.isBelongRoad(UIEvents.OneEdgeThreeLanRoad);
+    roadService.create(startPoint.vectorId, crossPoint.vectorId);
+    roadService.create(crossPoint.vectorId, endPoint.vectorId);
+    let startPoint2 = {
+      x: startPoint.x + roadLen / 4,
+      y: startPoint.y,
+    };
+    startPoint2 = roadPointService.create(startPoint2);
+    uiService.isBelongRoad(UIEvents.OneEdgeOneLanRoad);
+    roadService.create(startPoint2.vectorId, crossPoint.vectorId);
+    edgeService.updateEdgeForMulRoad(crossPoint.vectorId);
+  }
+
+  buildNationalHighwayShoulder(position) {
+    const roadLen = 600;
+    let startPoint = {
+      x: position.x,
+      y: position.y + roadLen / 2,
+    };
+    let endPoint = {
+      x: position.x,
+      y: position.y - roadLen / 2,
+    };
+    startPoint = roadPointService.create(startPoint);
+    endPoint = roadPointService.create(endPoint);
+    uiService.isBelongRoad(UIEvents.TwoEdgeTwoLanRoad);
+    roadService.create(startPoint.vectorId, endPoint.vectorId);
+  }
+
+  buildIndoorSection(position) {
+    const roadLen = 600;
+    let startPoint = {
+      x: position.x,
+      y: position.y + roadLen / 2,
+    };
+    let endPoint = {
+      x: position.x,
+      y: position.y - roadLen / 2,
+    };
+    startPoint = roadPointService.create(startPoint);
+    endPoint = roadPointService.create(endPoint);
+    uiService.isBelongRoad(UIEvents.TwoEdgeThreeLanRoad);
+    roadService.create(startPoint.vectorId, endPoint.vectorId);
+  }
+
+  buildBend(position) {
+    const roadLen = 500;
+    const offsetDis = 150;
+    let startPoint = {
+      x: position.x,
+      y: position.y + roadLen / 2,
+    };
+    let endPoint = {
+      x: position.x,
+      y: position.y - roadLen / 2,
+    };
+    startPoint = curveRoadPointService.create(startPoint);
+    endPoint = curveRoadPointService.create(endPoint);
+    uiService.setCurveRoadLeftDrivewayCount(2);
+    uiService.setCurveRoadRightDrivewayCount(2);
+    uiService.setLeftCurveRoadWidth(100);
+    uiService.setRightCurveRoadWidth(100);
+    const curveRoad = curveRoadService.create(
+      startPoint.vectorId,
+      endPoint.vectorId
+    );
+    const midPoint = {
+      x: (startPoint.x + endPoint.x) / 2 - offsetDis,
+      y: (startPoint.y + endPoint.y) / 2,
+    };
+    curveRoadService.updateForMovePoint(curveRoad.points[1].vectorId, midPoint);
+    uiService.setCurveRoadLeftDrivewayCount(1);
+    uiService.setCurveRoadRightDrivewayCount(1);
+    uiService.setLeftCurveRoadWidth(50);
+    uiService.setRightCurveRoadWidth(50);
+  }
+
+  buildSharpCurve(position) {
+    const roadLen = 650;
+    const height = 450;
+    let startPoint = {
+      x: position.x + roadLen,
+      y: position.y + height / 2,
+    };
+    let endPoint = {
+      x: position.x + roadLen,
+      y: position.y - height / 2,
+    };
+    startPoint = curveRoadPointService.create(startPoint);
+    endPoint = curveRoadPointService.create(endPoint);
+
+    uiService.setCurveRoadLeftDrivewayCount(2);
+    uiService.setCurveRoadRightDrivewayCount(2);
+    uiService.setLeftCurveRoadWidth(100);
+    uiService.setRightCurveRoadWidth(100);
+
+    let curveRoad = new CurveRoad(startPoint.vectorId, endPoint.vectorId);
+    dataService.addCurveRoad(curveRoad);
+
+    startPoint.setPointParent(curveRoad.vectorId);
+    startPoint.setIndex(0);
+
+    endPoint.setPointParent(curveRoad.vectorId);
+    endPoint.setIndex(2);
+
+    let edgePoints = mathUtil.RectangleVertex(
+      startPoint,
+      endPoint,
+      curveRoad.leftWidth +
+        curveRoad.rightWidth +
+        curveRoad.midDivide.midDivideWidth
+    );
+
+    let leftEdge = curveEdgeService.create(
+      edgePoints.leftEdgeStart,
+      edgePoints.leftEdgeEnd,
+      null,
+      curveRoad.vectorId
+    );
+
+    let rightEdge = curveEdgeService.create(
+      edgePoints.rightEdgeStart,
+      edgePoints.rightEdgeEnd,
+      null,
+      curveRoad.vectorId
+    );
+
+    curveRoad.setLeftEdge(leftEdge.vectorId);
+    curveRoad.setRightEdge(rightEdge.vectorId);
+
+    curveRoad.points.push(startPoint);
+    curveRoad.points.push(endPoint);
+
+    leftEdge.points.push(edgePoints.leftEdgeStart);
+    leftEdge.points.push(edgePoints.leftEdgeEnd);
+
+    rightEdge.points.push(edgePoints.rightEdgeStart);
+    rightEdge.points.push(edgePoints.rightEdgeEnd);
+
+    let point1 = {
+      x: position.x + 200,
+      y: position.y + height / 2,
+    };
+    let point2 = {
+      x: position.x + 50,
+      y: position.y + height / 2 - 50,
+    };
+    let point3 = {
+      x: position.x + 50,
+      y: position.y - height / 2 + 50,
+    };
+    let point4 = {
+      x: position.x + 200,
+      y: position.y - height / 2,
+    };
+
+    curveRoadService.addCPoint(curveRoad, point1, 0);
+    curveRoadService.addCPoint(curveRoad, point2, 1);
+    curveRoadService.addCPoint(curveRoad, position, 2);
+    curveRoadService.addCPoint(curveRoad, point3, 3);
+    curveRoadService.addCPoint(curveRoad, point4, 4);
+
+    curveRoadService.updateForMovePoint(curveRoad.points[1].vectorId, point1);
+    curveRoadService.updateForMovePoint(curveRoad.points[2].vectorId, point2);
+    curveRoadService.updateForMovePoint(curveRoad.points[3].vectorId, position);
+    curveRoadService.updateForMovePoint(curveRoad.points[4].vectorId, point3);
+    curveRoadService.updateForMovePoint(curveRoad.points[5].vectorId, point4);
+
+    uiService.setCurveRoadLeftDrivewayCount(1);
+    uiService.setCurveRoadRightDrivewayCount(1);
+    uiService.setLeftCurveRoadWidth(50);
+    uiService.setRightCurveRoadWidth(50);
+  }
+
+  buildCorner(position) {
+    const len = 300;
+    let end = roadPointService.create(position);
+    let start1 = roadPointService.create({
+      x: end.x + len,
+      y: end.y,
+    });
+
+    let start2 = roadPointService.create({
+      x: end.x,
+      y: end.y - len,
+    });
+
+    //需要设置公路的车道数,是否双向等等
+    uiService.isBelongRoad(UIEvents.TwoEdgeTwoLanRoad);
+
+    roadService.create(start1.vectorId, end.vectorId);
+    roadService.create(start2.vectorId, end.vectorId);
+    edgeService.updateEdgeForMulRoad(end.vectorId);
+  }
+
+  buildImportSmashedRoad(position) {
+    const roadLen = 600;
+    let startPoint = {
+      x: position.x,
+      y: position.y - (roadLen * 3) / 5,
+    };
+    let endPoint = {
+      x: position.x,
+      y: position.y + (roadLen * 2) / 5,
+    };
+    startPoint = roadPointService.create(startPoint);
+    endPoint = roadPointService.create(endPoint);
+    let crossPoint = roadPointService.create(position);
+
+    uiService.isBelongRoad(UIEvents.OneEdgeThreeLanRoad);
+    roadService.create(startPoint.vectorId, crossPoint.vectorId);
+    roadService.create(crossPoint.vectorId, endPoint.vectorId);
+    let startPoint2 = {
+      x: startPoint.x + roadLen / 4,
+      y: startPoint.y,
+    };
+    startPoint2 = roadPointService.create(startPoint2);
+    uiService.isBelongRoad(UIEvents.OneEdgeOneLanRoad);
+    roadService.create(startPoint2.vectorId, crossPoint.vectorId);
+    edgeService.updateEdgeForMulRoad(crossPoint.vectorId);
+  }
+
+  buildHighSpeedTollBooth(position) {
+    const roadLen = 600;
+    let startPoint = {
+      x: position.x,
+      y: position.y + roadLen / 2,
+    };
+    let endPoint = {
+      x: position.x,
+      y: position.y - roadLen / 2,
+    };
+    startPoint = roadPointService.create(startPoint);
+    endPoint = roadPointService.create(endPoint);
+    uiService.setWayType(Constant.oneWay);
+    uiService.setSingleRoadDrivewayCount(6);
+    uiService.setSingleRoadWidth(Settings.singleLaneWidth * 6);
+
+    roadService.create(startPoint.vectorId, endPoint.vectorId);
+  }
+
+  buildHighwaySection(position) {
+    const roadLen = 600;
+    let startPoint = {
+      x: position.x,
+      y: position.y + roadLen / 2,
+    };
+    let endPoint = {
+      x: position.x,
+      y: position.y - roadLen / 2,
+    };
+    startPoint = roadPointService.create(startPoint);
+    endPoint = roadPointService.create(endPoint);
+    uiService.isBelongRoad(UIEvents.TwoEdgeTwoLanRoad);
+    roadService.create(startPoint.vectorId, endPoint.vectorId);
+  }
+
+  //这个还没解决
+  buildHighSpeedHarbor(position) {}
+
+  //这个还没解决
+  buildWideNarrowRoad(position) {}
 }
 
 const addCrossRoad = new AddCrossRoad();

+ 6 - 0
src/graphic/Controls/UIControl.js

@@ -1,6 +1,8 @@
 import { coordinate } from "../Coordinate.js";
 import LayerEvents from "../enum/LayerEvents.js";
 import UIEvents from "../enum/UIEvents.js";
+import RoadTemplate from "../enum/RoadTemplate.js";
+import RoadStructure from "../enum/RoadStructure.js";
 import VectorType from "../enum/VectorType.js";
 import VectorStyle from "../enum/VectorStyle.js";
 import GeoActions from "../enum/GeoActions.js";
@@ -108,6 +110,10 @@ export default class UIControl {
           stateService.setEventName(LayerEvents.AddSVG);
         } else if (selectUI == UIEvents.Img) {
           stateService.setEventName(LayerEvents.Img);
+        } else if (uiService.isBelongRoadTemplate(selectUI)) {
+          stateService.setEventName(LayerEvents.AddRoadTemplate);
+        } else if (uiService.isBelongRoadStructure(selectUI)) {
+          stateService.setEventName(LayerEvents.AddRoadStructure);
         }
       }
     }

+ 20 - 7
src/graphic/Layer.js

@@ -10,6 +10,7 @@ import { moveText } from "./Controls/MoveText";
 import { moveSVG } from "./Controls/MoveSVG";
 import { moveMagnifier } from "./Controls/MoveMagnifier";
 import { addRoad } from "./Controls/AddRoad";
+import { addCrossRoad } from "./Controls/AddCrossRoad";
 import { addLine } from "./Controls/AddLine";
 import { addPoint } from "./Controls/AddPoint";
 import { addCircle } from "./Controls/AddCircle";
@@ -290,16 +291,23 @@ export default class Layer {
               position
             );
             if (dis1 > dis2) {
-              curveRoadService.addCPoint(
-                curveRoad,
-                position,
-                curveRoad.points.length - 2
-              );
+              index = curveRoad.points.length - 2;
+              // curveRoadService.addCPoint(
+              //   curveRoad,
+              //   position,
+              //   curveRoad.points.length - 2
+              // );
             } else {
-              curveRoadService.addCPoint(curveRoad, position, 1);
+              //curveRoadService.addCPoint(curveRoad, position, 1);
+              index = 1;
             }
+            curveRoadService.addCPoint(curveRoad, position, index);
           }
-          curveRoadService.setLanes(curveRoad.vectorId);
+          //curveRoadService.setLanes(curveRoad.vectorId);
+          curveRoadService.updateForMovePoint(
+            curveRoad.points[index + 1].vectorId,
+            position
+          );
           stateService.clearEventName();
           this.history.save();
           this.renderer.autoRedraw();
@@ -1175,6 +1183,11 @@ export default class Layer {
           elementService.hideAll();
         }
         break;
+      case LayerEvents.AddRoadTemplate:
+        addCrossRoad.build(position);
+        this.history.save();
+        this.renderer.autoRedraw();
+        break;
     }
 
     this.setEventName("mouseUp");

+ 2 - 6
src/graphic/Service/CurveRoadService.js

@@ -149,22 +149,18 @@ export default class CurveRoadService extends RoadService {
       edgePoints.leftEdgeStart,
       edgePoints.leftEdgeEnd,
       null,
-      vectorId
+      newCurveRoad.vectorId
     );
 
     let rightEdge = curveEdgeService.create(
       edgePoints.rightEdgeStart,
       edgePoints.rightEdgeEnd,
       null,
-      vectorId
+      newCurveRoad.vectorId
     );
 
     newCurveRoad.setLeftEdge(leftEdge.vectorId);
     newCurveRoad.setRightEdge(rightEdge.vectorId);
-    if (!vectorId) {
-      leftEdge.setEdgeParent(newCurveRoad.vectorId);
-      rightEdge.setEdgeParent(newCurveRoad.vectorId);
-    }
 
     newCurveRoad.points.push(newStartPoint);
     newCurveRoad.points.push(newEndPoint);

+ 52 - 0
src/graphic/Service/UIService.js

@@ -7,6 +7,8 @@ import UIEvents from "../enum/UIEvents.js";
 import VectorCategory from "../enum/VectorCategory.js";
 import Constant from "../Constant.js";
 import VectorStyle from "../enum/VectorStyle.js";
+import RoadTemplate from "../enum/RoadTemplate.js";
+import RoadStructure from "../enum/RoadStructure.js";
 
 export default class UIService {
   constructor() {}
@@ -129,6 +131,24 @@ export default class UIService {
     }
   }
 
+  isBelongRoadTemplate(ui) {
+    if (RoadTemplate[ui]) {
+      this.setSelectRoadTemplate(ui);
+      return true;
+    } else {
+      return false;
+    }
+  }
+
+  isBelongRoadStructure(ui) {
+    if (RoadStructure[ui]) {
+      this.setSelectRoadStructure(ui);
+      return true;
+    } else {
+      return false;
+    }
+  }
+
   setWayType(value) {
     Settings.wayType = value;
   }
@@ -165,6 +185,22 @@ export default class UIService {
     Settings.rightRoadWidth = value;
   }
 
+  setCurveRoadLeftDrivewayCount(value) {
+    Settings.curveRoadLeftDrivewayCount = value;
+  }
+
+  setCurveRoadRightDrivewayCount(value) {
+    Settings.curveRoadRightDrivewayCount = value;
+  }
+
+  setLeftCurveRoadWidth(value) {
+    Settings.leftCurveRoadWidth = value;
+  }
+
+  setRightCurveRoadWidth(value) {
+    Settings.rightCurveRoadWidth = value;
+  }
+
   setSelectLineCategory(value) {
     Settings.selectLineCategory = value;
   }
@@ -182,6 +218,22 @@ export default class UIService {
     Settings.selectSVGType = value;
   }
 
+  getSelectRoadTemplate() {
+    return Settings.selectRoadTemplate;
+  }
+
+  setSelectRoadTemplate(value) {
+    Settings.selectRoadTemplate = value;
+  }
+
+  setSelectRoadStructure(value) {
+    Settings.selectRoadStructure = value;
+  }
+
+  getSelectRoadStructure() {
+    return Settings.selectRoadStructure;
+  }
+
   //如果position在屏幕左上角,返回的就朝向右下角,如果是右下角,则返回的是左上角。其他情况以此类推
   getNewPositionForPop(position) {
     const offset = 50;

+ 4 - 2
src/graphic/Settings.js

@@ -25,7 +25,9 @@ const Settings = {
   selectPointCategory: VectorCategory.Point.NormalPoint,
   selectLocationMode: null,
   selectBasePointId: null, //选中的基准点
-  selectSVGType: null,
+  selectSVGType: null, //图例
+  selectRoadTemplate: null, //道路模板
+  selectRoadStructure: null, //道路结构
 };
-console.error(os.isPc)
+console.error(os.isPc);
 export default Settings;

+ 30 - 0
src/graphic/Util/MathUtil.js

@@ -1106,6 +1106,36 @@ export default class MathUtil {
     return points;
   }
 
+  createSixPoint(position, r) {
+    let deg = Math.PI / 180; //角度
+    let points = [];
+    points[0] = {
+      x: position.x,
+      y: position.y + r,
+    };
+    points[1] = {
+      x: position.x + r * Math.sin(60 * deg),
+      y: position.y + r * Math.cos(60 * deg),
+    };
+    points[2] = {
+      x: position.x + r * Math.cos(30 * deg),
+      y: position.y - r * Math.sin(30 * deg),
+    };
+    points[3] = {
+      x: position.x,
+      y: position.y - r,
+    };
+    points[4] = {
+      x: position.x - r * Math.cos(30 * deg),
+      y: position.y - r * Math.sin(30 * deg),
+    };
+    points[5] = {
+      x: position.x - r * Math.sin(60 * deg),
+      y: position.y + r * Math.cos(60 * deg),
+    };
+    return points;
+  }
+
   //求圆和直线之间的交点
   /**
    * 求圆和直线之间的交点

+ 3 - 0
src/graphic/enum/LayerEvents.js

@@ -48,5 +48,8 @@ const LayerEvents = {
 
   Img: "Img",
   MoveMeasureArrow: "moveMeasureArrow",
+
+  AddRoadTemplate: "addRoadTemplate",
+  AddRoadStructure: "addRoadStructure",
 };
 export default LayerEvents;

+ 39 - 18
src/sdk/laser/core/enter.js

@@ -161,7 +161,17 @@ var enter = ({
     };
     let getMeasureType = function (type, unit) {
         switch (type) {
-        case "LINE":
+
+
+        case 'BASE_LINE':
+            info = {
+                measureType: "Hor LINE with Text", //带有文字label的线
+                labelText : '基准线',
+                isBaseLine : true,      //暂时只有基准线是这种measureType
+            };
+            break;
+
+        case "LINE": 
             info = {
                 measureType: "Distance"
             };
@@ -334,9 +344,11 @@ var enter = ({
             //手动开启或关闭:
             show: () => {
                 Potree.Utils.updateVisible(measure, "inListByUser", true);
+                viewer.dispatchEvent('content_changed')
             },
             hide: () => {
                 Potree.Utils.updateVisible(measure, "inListByUser", false);
+                viewer.dispatchEvent('content_changed')
             },
             /* highlight: (isHight) => {
                 measure.setSelected(isHight, "byList");
@@ -405,6 +417,7 @@ var enter = ({
                         pos2d.clientY = pos2d.y;
                         pos2d.onlyGetIntersect = true;
                         pos2d.whichPointcloud = !Potree.settings.depTexLocBindDataset;
+                        pos2d.usePointcloud = true // 深度图不准
                         intersect = Handler.onMouseMove(pos2d);
                     }
                 } else {
@@ -421,7 +434,7 @@ var enter = ({
                         }); */
                 } else
                     return null;
-                //console.log(position, datasetId, dataset_location)
+                //console.log('getPointByScreen',position )
                 return {
                     position,
                     /* datasetId,
@@ -489,12 +502,12 @@ var enter = ({
              * 开始测量
              */
             startMeasure(type, unit, color) {
-                const bus = mitt();
+                const bus = mitt(); 
                 let info = getMeasureType(type, unit);
                 //info.bus = bus
-                info.color = color
-                let measure = viewer.measuringTool.startInsertion(
-                        info,
+                info.color = color 
+                
+                let measure = viewer.measuringTool.startInsertion( info,
                         () => {
                         //done:
                         bus.emit("end", ret); //完成
@@ -503,11 +516,14 @@ var enter = ({
                         //cancel
                         bus.emit("quit", ret); //删除
                     });
+                 
                 Potree.Log("startMeasure: " + measure.id, {
                     font: {
                         color: "#00c7b2"
                     },
                 });
+
+
                 viewer.setPointStandardMat(true);
                 const ret = {
                     bus,
@@ -543,6 +559,12 @@ var enter = ({
                 points_datasets,
                 sid, color) {
                 const bus = mitt();
+                
+                /* if(!viewer.scene.measurements.find(e=>e.isBaseLine)){
+                    type = 'BASE_LINE'
+                } 
+                 */
+                
                 let info = getMeasureType(type, unit);
                 info.points = points;
                 //info.datasetId = datasetId;
@@ -573,6 +595,7 @@ var enter = ({
 
             // 开启放大镜
             openMagnifier() {
+                //console.error('开启放大镜')
                 viewer.magnifier.dispatchEvent({
                     type: "setEnable",
                     value: true
@@ -580,6 +603,7 @@ var enter = ({
             },
             // 关闭放大镜
             closeMagnifier() {
+                //console.error('关闭放大镜')
                 viewer.magnifier.dispatchEvent({
                     type: "setEnable",
                     value: false
@@ -730,7 +754,7 @@ var enter = ({
                 } = viewer.startScreenshot({
                         type: "default",
                         hideMarkers:true,
-                        hideMeasures:true,
+                        //hideMeasures:true,
                     },
                         width,
                         height);
@@ -759,33 +783,30 @@ var enter = ({
             },
             
             
-            /* 
-            添加一个方法  单击场景某个位置 返回当前三维坐标,   调用时场景不能漫游与选择直到获取完成
-            sdk.scene.trackScenePos()
-            返回
-            {
-              promise: Promise<Pos3D>,   //获取的promise, 获取到了返回三维坐标,没获取到返回null
-              quit: function()  //取消获取 
-            }志彬5月15日 14:46 */
+           
   
-            trackScenePos(){
+            trackScenePos(){// 单击场景某个位置 返回当前三维坐标,   调用时场景不能漫游与选择直到获取完成
                 let deferred = $.Deferred();
                 let quit = ()=>{ //取消获取 
                     viewer.removeEventListener('global_click',gotIntersect)
                     Potree.settings.unableNavigate = false 
-                    viewer.controls.setEnable(true) 
+                    Potree.settings.unableUseDepTexPick = false
+                    viewer.controls.setEnable(true)  
                 }
                 
                 let gotIntersect = (e)=>{
                     if(e.intersect && e.intersect.location){ 
                         console.log('quit', e.intersect.location)
                         quit()
-                        deferred.resolve(e.intersect.location)
+                        deferred.resolve(e.intersect.location) 
                     } 
                 }
                 
                 viewer.addEventListener('global_click',gotIntersect) 
                 Potree.settings.unableNavigate = true
+                Potree.settings.unableUseDepTexPick = true 
+
+
                 viewer.controls.setEnable(false)
                 
                 return {

+ 2 - 1
src/store/photos.ts

@@ -4,6 +4,7 @@ import {Pos} from "@/sdk";
 export type PhotoRaw = {
   id: string
   url: string
+  urlRaw: string
   meterPerPixel: number
   time: number,
   measures: { pos: Pos[], dis: number}[],
@@ -12,4 +13,4 @@ export type PhotoRaw = {
   baseLines: Array<Pos[]>
 }
 
-export const photos = ref<PhotoRaw[]>([])
+export const photos = ref<PhotoRaw[]>([])

+ 9 - 2
src/views/photos/index.vue

@@ -9,6 +9,7 @@
     </template>
 
     <Photos
+      :getURL="data => data.urlRaw || data.url"
       v-model:active="active"
       v-model:selects="selects"
       :select-mode="selectMode"
@@ -21,7 +22,13 @@
     <ActionMenus class="select-menus" :menus="selectMenus" dire="row" v-if="selects.length" />
   </MainPanel>
 
-  <FillSlide :data="sortPhotos" v-model:active="active" @quit="active = null" v-if="active">
+  <FillSlide
+      :data="sortPhotos"
+      v-model:active="active"
+      @quit="active = null"
+      v-if="active"
+      :getURL="data => data.urlRaw || data.url"
+  >
     <template v-slot:foot>
       <ActionMenus class="menus" :menus="menus" dire="row" />
     </template>
@@ -156,4 +163,4 @@ onDeactivated(() => {
   bottom: var(--boundMargin);
 }
 
-</style>
+</style>

+ 4 - 1
src/views/scene/covers/cover.vue

@@ -15,7 +15,7 @@
 <script setup lang="ts">
 import {computed, onMounted, onUnmounted, ref, watch} from 'vue'
 import {Pos, Pos3D} from '@/sdk'
-import {useSDK} from '@/hook'
+import {customMap, useSDK} from '@/hook'
 import { getPostionByTarget} from '@/components/base/utils'
 
 const props = defineProps<{
@@ -50,6 +50,7 @@ updatePos()
 
 const move = ref(false)
 const downHandler = (sev: MouseEvent | TouchEvent) => {
+  customMap.magnifier = true
   const start = new Date().getTime()
   const el = sev.target as HTMLElement
   const mountEl = document.documentElement
@@ -83,6 +84,8 @@ const downHandler = (sev: MouseEvent | TouchEvent) => {
     mountEl.removeEventListener('touchmove', moveHandler)
     mountEl.removeEventListener('touchend', upHandler)
     move.value = false
+    customMap.magnifier = false
+    console.log("关闭放大镜")
     if (new Date().getTime() - start < 300) {
       clickHandler(ev)
     }

+ 3 - 2
src/views/scene/index.vue

@@ -3,12 +3,12 @@
 
   <template v-if="loaded">
     <Mode />
-    <Menus />
+    <Menus @enter-child="childPage = true" @leave-child="childPage = false" />
     <BasePoints />
     <FixPoints />
     <Measures />
     <Photo />
-    <ButtonPane class="back fun-ctrl" size="48" @click="back">
+    <ButtonPane class="back fun-ctrl" size="48" @click="back" v-if="!childPage">
       <ui-icon type="close" class="icon" />
     </ButtonPane>
   </template>
@@ -30,6 +30,7 @@ import {ref, watchEffect} from "vue";
 import {back} from "@/store/sync";
 
 const loaded = ref(false)
+const childPage = ref(false)
 const stopReg = watchEffect(() => {
   if (loaded.value) {
     const sdk = useSDK();

+ 16 - 6
src/views/scene/menus/actions.ts

@@ -12,14 +12,14 @@ import Message from "@/components/base/components/message/message.vue";
 import { getId } from '@/utils'
 
 const trackPosMenuAction = (onComplete: () => void, onAddStore: (pos: Pos3D) => void) => {
-  customMap.magnifier = true
+  // customMap.magnifier = true
 
   const onCleanup = getCoverPos(pos => {
     onComplete()
     onAddStore(pos)
   })
   return () => {
-    customMap.magnifier = false
+    // customMap.magnifier = false
     onCleanup()
   }
 }
@@ -73,24 +73,34 @@ const trackMeasureMenuAction = (
 
 const menuActions = {
   [menuEnum.BASE_POINT]: (_, onComplete) => {
-    const hide = Message.success({ msg: "请单击选择基准点位置" })
-    return trackPosMenuAction(
+    let hide = Message.success({ msg: "请单击选择基准点位置" })
+    const onDestroy = trackPosMenuAction(
       () => {
         hide()
+        hide = null
         onComplete()
       },
       pos => basePoints.value.push({ id: getId(), pos })
     )
+    return () => {
+      onDestroy()
+      hide && hide()
+    }
   },
   [menuEnum.FIX_POINT]:  (_, onComplete) => {
-    const hide = Message.success({ msg: "请单击选择固定点位置" })
-    return trackPosMenuAction(
+    let hide = Message.success({ msg: "请单击选择固定点位置" })
+    const onDestroy = trackPosMenuAction(
       () => {
         hide()
+        hide = null
         onComplete()
       },
       pos => fixPoints.value.push({ id: getId(), pos, text: "其他散落物" })
     )
+    return () => {
+      onDestroy()
+      hide && hide()
+    }
   },
   [menuEnum.MEASURE_ROW]: (menu, onComplete) => {
     return trackMeasureMenuAction(

+ 5 - 0
src/views/scene/menus/menus.ts

@@ -9,6 +9,7 @@ export type MenuRaw = {
   key: string,
   text: string,
   continued?: boolean
+  defaultSelect?: true | (() => boolean),
   icon?: string,
   disabled?: boolean | (() => boolean),
   children?: MenuRaw[],
@@ -46,6 +47,7 @@ export const menus: MenuRaw[] = [
         icon: "line_h",
         // continued: true,
         text: "水平",
+        defaultSelect: true,
         key: menuEnum.MEASURE_ROW
       },
       {
@@ -68,6 +70,7 @@ export const menus: MenuRaw[] = [
     key: "fixPointMenu",
     children: [
       {
+        defaultSelect: true,
         icon: "point_a",
         text: "固定点",
         key: menuEnum.FIX_POINT
@@ -97,12 +100,14 @@ export const menus: MenuRaw[] = [
     },
     children: [
       {
+        defaultSelect: () => !baseLines.value.length,
         icon: "line",
         text: "基准线",
         key: menuEnum.BASE_LINE,
         disabled: () => !!baseLines.value.length
       },
       {
+        defaultSelect: true,
         icon: "point",
         text: "基准点",
         key: menuEnum.BASE_POINT

+ 29 - 3
src/views/scene/menus/pane.vue

@@ -18,14 +18,18 @@
 import ActionMenus from "@/components/group-button/index.vue";
 import {generateMixMenus, MenuRaw, menus, findMenuByKey} from './menus'
 import {joinActions} from './actions'
-import {computed, onUnmounted, watchEffect} from "vue";
+import {computed, onMounted, onUnmounted, watchEffect} from "vue";
 import {disabledMap} from "@/hook";
 
 const props = withDefaults(
   defineProps<{ menus?: MenuRaw[], level?: number }>(),
   {level: 1}
 )
-const emit = defineEmits<{ (e: 'back'): void }>();
+const emit = defineEmits<{
+  (e: 'back'): void,
+  (e: 'enterChild'): void,
+  (e: 'leaveChild'): void,
+}>();
 const backMenu = {
   icon: "return",
   text: "",
@@ -56,8 +60,30 @@ if (props.level === 1) {
   watchEffect(() => {
     disabledMap.photo = !store.child.value?.length
   })
+  watchEffect(() => {
+    if (store.child.value) {
+      emit('enterChild')
+    } else {
+      emit('leaveChild')
+    }
+  })
 }
+
 onUnmounted(joinActions(store.itemActiveKey));
+onMounted(() => {
+  if (props.level > 1) {
+    const defaultMenu = props.menus.find(menu => {
+      if (typeof menu.defaultSelect === 'function') {
+        return menu.defaultSelect()
+      } else {
+        return menu.defaultSelect
+      }
+    })
+    console.log(defaultMenu)
+    store.itemActiveKey.value = defaultMenu?.key
+    // store.activeMenuKey.value =
+  }
+})
 </script>
 <script lang="ts"> export default {name: 'scene-menus'}</script>
 
@@ -69,4 +95,4 @@ onUnmounted(joinActions(store.itemActiveKey));
   transform: translateY(-50%);
   z-index: 2;
 }
-</style>
+</style>

+ 41 - 26
src/views/scene/photo.vue

@@ -30,7 +30,7 @@ import {base64ToBlob, getId} from "@/utils";
 import {nextTick, ref} from "vue";
 import {api, downloadImage, uploadImage} from "@/store/sync";
 import {router, writeRouteName} from "@/router";
-import {Pos, Pos3D} from "@/sdk";
+import {LaserSDK, Pos, Pos3D} from "@/sdk";
 
 const showCoverUrl = ref<string>()
 if (photos.value[photos.value.length - 1]?.url) {
@@ -45,37 +45,57 @@ const getCurrentScreen = (pos: Pos3D): Pos => {
   const data = sdk.scene.getScreenByPoint(pos)
   return data.trueSide ? data.pos : null
 }
+
+const screenshot = async (sdk: LaserSDK) => {
+  const dom = sdk.scene.el
+  dom.style.pointerEvents = "none"
+
+  const getScreenshot = async () => {
+    const data = sdk.scene.screenshot(
+      dom.offsetWidth,
+      dom.offsetHeight
+    )
+    const {dataUrl: base64} = await data.finishPromise
+    const url = await uploadImage(base64ToBlob(base64))
+    return {
+      url,
+      meterPerPixel: data.meterPerPixel
+    }
+  }
+  const screenshotRaw = await getScreenshot()
+
+  baseLines.value.concat(list.value).forEach(item => item.show = false)
+  await nextTick()
+  const screenshot = await getScreenshot()
+  baseLines.value.concat(list.value).forEach(item => item.show = true)
+  await nextTick()
+
+  dom.style.pointerEvents = "all"
+  return {
+    rawUrl: screenshotRaw.url,
+    url: screenshot.url,
+    meterPerPixel: screenshot.meterPerPixel
+  }
+}
+
 const getCurrentScreens = (poss: Array<Pos3D>): Array<Pos> =>
   poss.map(getCurrentScreen).filter(pos => !!pos);
 
 const photo = genUseLoading(async () => {
   const sdk = useSDK()
-  const dom = sdk.scene.el
-  dom.style.pointerEvents = "none"
-
-  const data = sdk.scene.screenshot(
-    dom.offsetWidth,
-    dom.offsetHeight
-  )
-  const {dataUrl: base64} = await data.finishPromise
-  const blob = base64ToBlob(base64)
-  tempPhoto.value = URL.createObjectURL(blob)
+  const data = await screenshot(sdk)
+  tempPhoto.value = await api.getFile(data.rawUrl)
+  await nextTick()
 
-  const upload = uploadImage(blob)
-  await nextTick();
   const handler = async () => {
     coverRef.value.removeEventListener("animationend", handler)
     showCoverUrl.value = tempPhoto.value
     tempPhoto.value = null
-    // baseLines.value.concat(list.value).forEach(item => {
-    //   item.show = false
-    // })
-    await nextTick()
-    // await downloadImage(blob)
-    const url = await upload
+
     photos.value.push({
       id: getId(),
-      url: url,
+      url: data.url,
+      urlRaw: data.rawUrl,
       time: new Date().getTime(),
       meterPerPixel: data.meterPerPixel,
       measures: list.value
@@ -96,11 +116,6 @@ const photo = genUseLoading(async () => {
         .filter(data => !!data.pos),
       basePoints: getCurrentScreens(basePoints.value.map(data => data.pos))
     })
-    showCoverUrl.value = await api.getFile(url)
-    dom.style.pointerEvents = "all"
-    // baseLines.value.concat(list.value).forEach(item => {
-    //   item.show = true
-    // })
   }
   coverRef.value.addEventListener("animationend", handler)
 })
@@ -187,4 +202,4 @@ const photo = genUseLoading(async () => {
   }
 
 }
-</style>
+</style>