Bläddra i källkod

土方量写完一版

xzw 1 år sedan
förälder
incheckning
7784b2c404

+ 3 - 25
src/custom/modules/siteModel/BuildingBox.js

@@ -139,10 +139,8 @@ export class BuildingBox extends ctrlPolygon{//建筑实体,包括building, fl
         if(this.ifDraw){ //只存储空间模型信息,不绘制
             
             {
-                this.lineMesh = LineDraw.createLine([],{color})
-                this.lineMesh.name = 'buildingLines'
-                this.lineMesh.visible = false            
-                this.add(this.lineMesh) 
+                this.createPrismLines(color) 
+                this.lineMesh.visible = false 
                 Potree.Utils.setObjectLayers(this.lineMesh, 'bothMapAndScene' ) 
             }
             
@@ -538,27 +536,7 @@ export class BuildingBox extends ctrlPolygon{//建筑实体,包括building, fl
         }
         
         
-        
-        {//update lines
-            
-            let positions = [];
-           
-            this.points.forEach((point, index)=>{
-                
-                //竖线:
-                positions.push(point.clone().setZ(this.zMin), point.clone().setZ(this.zMax))
-                
-                //横线
-                let nextPoint = this.points[(index+1)%length]; 
-                if(!nextPoint)return;//when length==1
-                
-                positions.push(point.clone().setZ(this.zMax), nextPoint.clone().setZ(this.zMax))//上横线
-                positions.push(point.clone().setZ(this.zMin), nextPoint.clone().setZ(this.zMin))//下横线
-            }) 
-            
-            LineDraw.moveLine(this.lineMesh,positions)
-             
-        }
+        this.updatePrismLines()//update lines
         
         if(!options.dontUpdateChildren){
             if(this.buildType == 'building'  ){

+ 2 - 2
src/custom/objects/Sprite.js

@@ -165,7 +165,7 @@ export default class Sprite extends THREE.Mesh{
                 }
                 
                 
-                let r1 = Potree.Utils.getPos2d(center,   e.viewport,  viewer.renderArea ); 
+                let r1 = Potree.Utils.getPos2d(center,   e.viewport,  viewer.renderArea, viewer.renderer); 
                 if(!r1.trueSide)return  setVisi(false);// 但这句会使realVisible为false从而无法更新//console.error('!r1.trueSide') //中心点如果在背面直接不渲染了
                     
                 let r2, point2
@@ -174,7 +174,7 @@ export default class Sprite extends THREE.Mesh{
                 while(p2State != 'got' && p2StateHistory.length<10){ 
                     point2 = center.clone().add(this.root.lineDir.clone().multiplyScalar(len));
                      
-                    r2 = Potree.Utils.getPos2d(point2, e.viewport , viewer.renderArea  );  
+                    r2 = Potree.Utils.getPos2d(point2, e.viewport , viewer.renderArea, viewer.renderer  );  
                     if(!r2.trueSide){ //很少遇到点2在背面的
                         if(!p2StateHistory.includes('tooLong-reverse')){
                             p2State = 'tooLong-reverse'  //先尝试反向

+ 109 - 8
src/custom/objects/TextSprite.js

@@ -39,7 +39,7 @@ export class TextSprite extends THREE.Object3D{
         this.borderColor = options.borderColor  ? Common.CloneObject(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.setText(options.text)
         this.name = options.name 
          
 		//this.setText(text);
@@ -48,13 +48,15 @@ export class TextSprite extends THREE.Object3D{
         this.addEventListener('dispose', this.dispose.bind(this)) 
 	}
 
-	setText(text){
-		if (this.text !== text){
-			this.text = text + '';
-
-			this.updateTexture();
+	setText(text){  
+        if(text == void 0)text = ''
+        if (this.text !== text) {
+            if (!(text instanceof Array)) {
+                this.text = [text + '']
+            } else this.text = text
+            this.updateTexture()
             this.sprite.waitUpdate() //重新计算各个viewport的matrix 
-		}
+        }
 	}
 
 	setTextColor(color){
@@ -87,7 +89,7 @@ export class TextSprite extends THREE.Object3D{
     setUniforms(name,value){
         this.sprite.setUniforms(name,value)
     }
-	updateTexture(){
+	updateTexture1(){
 		let canvas = document.createElement('canvas');
 		let context = canvas.getContext('2d');
         const r = window.devicePixelRatio
@@ -164,7 +166,106 @@ export class TextSprite extends THREE.Object3D{
         
          
 	}
+    
+    
+    
+    updateTexture(){
+       
+		let canvas = document.createElement('canvas');
+		let context = canvas.getContext('2d');
+        const r = window.devicePixelRatio
+		context.font = this.fontWeight + ' ' + this.fontsize * r + 'px ' + this.fontface; 
+       
+        //context["font-weight"] = 100; //语法与 CSS font 属性相同。
+		 
+        //this.text = '啊啊啊啊啊啊fag'
+        let textMaxWidth = 0,
+            infos = []
+        for (let text of this.text) {
+            let metrics = context.measureText(text)
+            let textWidth = metrics.width
+            infos.push(metrics)
+            textMaxWidth = Math.max(textMaxWidth, textWidth)
+        }
+         
+		let margin = (this.margin ? new THREE.Vector2().copy(this.margin) : new THREE.Vector2(this.fontsize, Math.max(  this.fontsize*0.4, 10)  )).clone().multiplyScalar(r); 
+		const lineSpace = (this.fontsize + margin.y) * 0.5
+        let spriteWidth = 2 * margin.x + textMaxWidth + 2 * this.rectBorderThick * r ;
+		let spriteHeight = 2 * margin.y + this.fontsize * r * this.text.length + 2 * this.rectBorderThick * r + lineSpace * (this.text.length - 1); 
+		context.canvas.width = spriteWidth;
+		context.canvas.height = spriteHeight;
+		context.font = this.fontWeight + ' ' + this.fontsize * r + 'px ' + this.fontface; 
+ 
+        /* let diff = 2//针对英文大部分在baseLine之上所以降低一点(metrics.fontBoundingBoxAscent - metrics.fontBoundingBoxDescent) / 2
 
+        context.textBaseline = "middle"
+         */
+        let expand = Math.max(1, Math.pow(this.fontsize / 16, 1.3)) * r  // 针对英文大部分在baseLine之上所以降低一点,或者可以识别当不包含jgqp时才加这个值  
+         
+        //canvas原点在左上角
+        context.textBaseline = 'alphabetic' //  "middle"  //设置文字基线。当起点y设置为0时,只有该线以下的部分被绘制出来。middle时文字显示一半(但是对该字体所有字的一半,有的字是不一定显示一半的,尤其汉字),alphabetic时是英文字母的那条基线。
+              
+        // border color
+        context.strokeStyle = 'rgba(' + this.borderColor.r + ',' + this.borderColor.g + ',' + this.borderColor.b + ',' + this.borderColor.a + ')';
+            
+        let rectBorderThick = this.rectBorderThick * r; 
+        context.lineWidth = rectBorderThick
+		// background color
+		context.fillStyle = 'rgba(' + this.backgroundColor.r + ',' + this.backgroundColor.g + ',' + this.backgroundColor.b + ',' + this.backgroundColor.a + ')';
+        this.roundRect(context, rectBorderThick / 2 , rectBorderThick / 2, spriteWidth - rectBorderThick, spriteHeight - rectBorderThick, this.borderRadius * r);
+        
+        context.fillStyle = 'rgba(' + this.textColor.r + ',' + this.textColor.g + ',' + this.textColor.b + ',' + this.textColor.a + ')'
+ 
+        
+        
+        let y = margin.y
+        for (let i = 0; i < this.text.length; i++) {
+            //let actualHeight = metrics.actualBoundingBoxAscent + metrics.actualBoundingBoxDescent // 当前文本字符串在这个字体下用的实际高度
+
+            //文字y向距离从textBaseline向上算
+            let actualBoundingBoxAscent = infos[i].actualBoundingBoxAscent == void 0 ? this.fontsize * r * 0.8 : infos[i].actualBoundingBoxAscent //有的流览器没有。只能大概给一个
+            y += actualBoundingBoxAscent + expand
+            //console.log(actualBoundingBoxAscent)
+
+            //console.log(this.text, 'y' , y, 'actualBoundingBoxAscent', metrics.actualBoundingBoxAscent,'expand',expand )
+            let textLeftSpace = (textMaxWidth - infos[i].width) / 2
+            let x = this.rectBorderThick + margin.x + textLeftSpace
+            // text color
+            if (this.textBorderThick) {
+                context.strokeStyle = 'rgba(' + this.textBorderColor.r + ',' + this.textBorderColor.g + ',' + this.textBorderColor.b + ',' + this.textBorderColor.a + ')'
+                context.lineWidth = this.textBorderThick * r
+                context.strokeText(this.text[i], x, y)
+            }
+              
+            if (this.textshadowColor) {
+                context.shadowOffsetX = 0
+                context.shadowOffsetY = 0
+                context.shadowColor = this.textshadowColor
+                context.shadowBlur = 12 * r
+            }
+            context.fillText(this.text[i], x, y)
+
+            y += lineSpace
+        } 
+        
+		let texture = new THREE.Texture(canvas);
+		texture.minFilter = THREE.LinearFilter;
+		texture.magFilter = THREE.LinearFilter;
+		texture.needsUpdate = true;
+		//this.material.needsUpdate = true; 
+        
+        if(this.sprite.material.map){
+            this.sprite.material.map.dispose()
+        }
+		this.sprite.material.map = texture;
+		  
+		this.sprite.scale.set(spriteWidth * 0.01 / r, spriteHeight * 0.01 / r, 1.0);
+        
+        
+	 
+    
+    }
+    
 	roundRect(ctx, x, y, w, h, r){
 		ctx.beginPath();
 		ctx.moveTo(x + r, y);

+ 8 - 12
src/custom/objects/tool/Measure.js

@@ -160,13 +160,10 @@ export class Measure extends ctrlPolygon{
      
     updateDatasetBelong(changeIndex){//更新所属数据集
      
-        if(Potree.settings.editType == "merge"){//无地图
-            /* this.dataset_points = this.points.map((e,i)=>{ 
-                return Potree.Utils.datasetPosTransform({toDataset:true, datasetId:this.points_datasets[i], position:e.clone()})
-            }) */
+        if(Potree.settings.editType == "merge" || this.measureType == 'MulDistance Ring'){//无地图
+          
             this.dataset_points[changeIndex] = Potree.Utils.datasetPosTransform({toDataset:true, datasetId:this.points_datasets[changeIndex], position:this.points[changeIndex].clone()})
-            
-            
+             
             return
         }
     
@@ -290,7 +287,7 @@ export class Measure extends ctrlPolygon{
                 let edgeLabel = this.edgeLabels[index];
                 let distance = point.distanceTo(nextPoint)
                 edgeLabel.shouldVisi = (index < lastIndex || this.isRect || this.closed && !this.isNew ) && distance>0 
-                /* this.closed || */edgeLabel.setVisible(edgeLabel.shouldVisi)  
+                this.closed || edgeLabel.setVisible(edgeLabel.shouldVisi)  //closed的在setEdgesDisplay中设置
                 
                 if(edgeLabel.shouldVisi){
                     edgeLabel.lineDir = new THREE.Vector3().subVectors(point,nextPoint).normalize() //[point,nextPoint]
@@ -338,7 +335,7 @@ export class Measure extends ctrlPolygon{
            
             let msg = this.getArea().string
             
-            this.areaLabel.setPos(this.center);
+            this.areaLabel.setPos(this.getCenter('areaPlaneCenter'))
             this.areaLabel.setText(msg);
             this.areaLabel.setVisible(true)
              
@@ -835,7 +832,7 @@ export class Measure extends ctrlPolygon{
 		return this.getAngleBetweenLines(point, previous, next);
 	}
     
-    getCenter(/* update */){ 
+    getCenter(type){  
         if(this.center){
             return this.center.clone()
         }else{  
@@ -998,7 +995,7 @@ export class Measure extends ctrlPolygon{
     
     
     getLineMat(type) { 
-        if(!Measure.lineMats){
+        if(!Measure.lineMats){ 
             Measure.lineMats = { 
                 edgeDefault:  LineDraw.createFatLineMat($.extend({},lineDepthInfo,{ 
                     color: config.measure.default.color, 
@@ -1026,8 +1023,7 @@ export class Measure extends ctrlPolygon{
                     gapSize: 0.02,
                     dashed: true,
                     lineWidth: config.measure.lineWidth/2  
-                }))
-                    
+                })), 
             }
         }
         return Measure.lineMats[type]

+ 3 - 3
src/custom/objects/tool/MeasuringTool.js

@@ -557,7 +557,7 @@ export class MeasuringTool extends THREE.EventDispatcher{
             if(e.measure && e.measure != measure || !viewer.scene.measurements.includes(measure) || !measure.isNew){
                 return;//若指定了退出的measure但和该measure不一致,就返回
             } 
-            if(e.remove){
+            if(e.remove || e.type == 'cancel_insertions'){
                 viewer.scene.removeMeasurement(measure)  
             }
             
@@ -702,7 +702,7 @@ export class MeasuringTool extends THREE.EventDispatcher{
     
 	render(o={}){
         if(this.scene.children.filter(e=>e.visible).length == 0)return
-        
+        let renderer = o.renderer || this.viewer.renderer
         Potree.Utils.setCameraLayers(o.camera, ['measure'])
 		
         /* if(o.screenshot && this.viewer.fxaaPass.enabled){ //抗锯齿
@@ -711,7 +711,7 @@ export class MeasuringTool extends THREE.EventDispatcher{
         }else{ */
         
             viewer.dispatchEvent({type: "render.begin2" , name:'measure', viewport:o.viewport  })
-            this.viewer.renderer.render(this.scene, o.camera );
+            renderer.render(this.scene, o.camera );
         //}
 	}
     

+ 46 - 4
src/custom/objects/tool/ctrlPolygon.js

@@ -69,13 +69,13 @@ export class ctrlPolygon extends THREE.Object3D {
             }
             
             
-            if(Potree.settings.editType != 'merge'){ 
+            if(Potree.settings.editType != 'merge' && this.measureType != 'MulDistance Ring'){ 
                 if(this.datasetId != void 0){//初始化位置
                     if(this.dataset_points){
                         this.dataset_points = this.dataset_points.map(e=>{
                             return e && new THREE.Vector3().copy(e) 
                         })
-                        this.transformByPointcloud() //根据dataset_points生成points  
+                        this.transformByPointcloud() //根据dataset_points和this.datasetId生成points  
                     }  
                 }else{
                     if(prop.dataset_points && prop.dataset_points.some(e=>e != void 0)){
@@ -198,7 +198,12 @@ export class ctrlPolygon extends THREE.Object3D {
                 if(this.points_datasets){
                     if(e.intersect.pointcloud) this.points_datasets[i] = e.intersect.pointcloud.dataset_id
                     else if(e.intersect.object) this.points_datasets[i] = e.intersect.object.dataset_id
-                    else this.points_datasets[i] = null
+                    else{ 
+                        if(this.measureType == 'MulDistance Ring'){//因为它的每个point跟着各自的dataset走,而不是整体的dataset
+                            let pointcloud = viewer.findClosestDatasetOnMap(I) || viewer.scene.pointclouds[0]
+                            this.points_datasets[i] = pointcloud.dataset_id
+                        }else this.points_datasets[i] = null
+                    }
                 }
             }
             this.editStateChange(true)
@@ -630,7 +635,7 @@ export class ctrlPolygon extends THREE.Object3D {
                 let points2d = this.points.map(e=>e.clone().setZ(z))
                 this.areaPlane.geometry = MeshDraw.getShapeGeo(points2d) //z=0
                 let center = math.getCenterOfGravityPoint(points2d) //重心 
-                this.center = new THREE.Vector3(center.x, center.y, z)
+                this.areaPlaneCenter = new THREE.Vector3(center.x, center.y, z)
                 this.areaPlane.position.z = z
                 
             }
@@ -692,6 +697,43 @@ export class ctrlPolygon extends THREE.Object3D {
         
     } 
     
+    
+    
+    createPrismLines(color){
+        this.lineMesh = LineDraw.createLine([],{color})
+        this.lineMesh.name = 'PrismLines' 
+        this.add(this.lineMesh)  
+    }
+    
+    updatePrismLines(){
+        if(!this.lineMesh)return
+        let positions = [];
+        let length = this.points.length
+        this.points.forEach((point, index)=>{
+            
+            //竖线:
+            positions.push(point.clone().setZ(this.zMin), point.clone().setZ(this.zMax))
+            
+            //横线
+            let nextPoint = this.points[(index+1)%length]; 
+            if(!nextPoint)return;//when length==1
+            
+            positions.push(point.clone().setZ(this.zMax), nextPoint.clone().setZ(this.zMax))//上横线
+            positions.push(point.clone().setZ(this.zMin), nextPoint.clone().setZ(this.zMin))//下横线
+        }) 
+        
+        LineDraw.moveLine(this.lineMesh,positions)
+        viewer.dispatchEvent('content_changed')
+    }
+    
+    
+    
+    
+    
+    
+    
+    
+    
     dispose(){//add 
         this.parent.remove(this)
         this.markers.concat(this.edges).forEach(e=>e.dispatchEvent({type:'dispose'})) 

+ 16 - 8
src/custom/potree.shim.js

@@ -445,7 +445,7 @@ Utils.mouseToRay = function(pointer, camera  ){
     return ray;
 }
 
-Utils.getPos2d = function(point, viewport , dom  ){//获取一个三维坐标对应屏幕中的二维坐标
+Utils.getPos2d = function(point, viewport , dom, renderer  ){//获取一个三维坐标对应屏幕中的二维坐标 
     var pos
     if(math.closeTo(viewport.camera.position, point, 1e-5) ){ //和相机位置重合时显示会四处飘,看是要改成一直显示中间还是隐藏?
         pos = new THREE.Vector3(0,0,1.5); //1.5是为了不可见
@@ -453,27 +453,35 @@ Utils.getPos2d = function(point, viewport , dom  ){//获取一个三维坐标对
         pos = point.clone().project(viewport.camera)	//比之前hotspot的计算方式写得简单  project用于3转2(求法同shader); unproject用于2转3 :new r.Vector3(e.x, e.y, -1).unproject(this.camera);
     }
     
+    let size = renderer && renderer.getSize(new THREE.Vector2) //如果是渲染到renderTarget上,resolution和dom的大小不一致。如果输出的结果给前端2d用,就使用clinetWidth,如果自己场景用,用renderer.size
+    let w = renderer ? size.x : dom.clientWidth
+    let h = renderer ? size.y : dom.clientHeight
+    
     
     var x,y,left,top;
-    x = (pos.x + 1) / 2 * dom.clientWidth * viewport.width;
-    y = (1 - (pos.y + 1) / 2) * dom.clientHeight * viewport.height; 
-    left = viewport.left * dom.clientWidth;
-    top = (1- viewport.bottom - viewport.height) * dom.clientHeight;
+    x = (pos.x + 1) / 2 * w * viewport.width;
+    y = (1 - (pos.y + 1) / 2) * h * viewport.height; 
+    left = viewport.left * w;
+    top = (1- viewport.bottom - viewport.height) * h;
      
 
     var inSight = pos.x <= 1 &&  pos.x >= -1    //是否在屏幕中   
                 && pos.x <= 1 &&  pos.y >= -1 
  
-
+    
     return {
-        pos:  new THREE.Vector2(left+x,top+y) ,// 屏幕像素坐标
+        pos:  new THREE.Vector2(left+x,top+y) ,// 屏幕像素坐标    
         vector:  pos,   //(范围 -1 ~ 1)
         trueSide : pos.z<1, //trueSide为false时,即使在屏幕范围内可见,也是反方向的另一个不可以被渲染的点   参见Tag.update
         inSight : inSight,	//在屏幕范围内可见,
-        posInViewport: new THREE.Vector2(x,y)
+        posInViewport: new THREE.Vector2(x,y),
+         
     };
 } 
 
+
+ 
+
 Utils.screenPass = new function () {
 	this.screenScene = new THREE.Scene();
 	this.screenQuad = new THREE.Mesh(new THREE.PlaneBufferGeometry(2, 2, 1));

+ 6 - 1
src/custom/settings.js

@@ -147,8 +147,13 @@ const config = {//配置参数   不可修改
             maxLevelPercent: 1,  
             pointBudget: 8*1000*1000,
             minNodeSize :   40 / window.devicePixelRatio  ,  
+        },
+        ultraHigh:{
+            maxLevelPercent: 1,  
+            pointBudget: 20*1000*1000,  
+            minNodeSize :   10 / window.devicePixelRatio, 
         }
- 
+        
         //数值由testLevelSteps得来,其中nodeMaxLevel为2时,low和middle的都是1,如果真有这么低的点云就单独处理下。
         //多个viewport尽量保证pointBudget一样,或者pointBudget不能太低于所需,否则会反复加载了又清除
     },  

+ 12 - 4
src/custom/utils/Common.js

@@ -315,14 +315,22 @@ var Common = {
         },
     }
     ,
-    pushToGroupAuto : function(items, groups, recognizeFunction){//自动分组。 items是将分到一起的组合。items.length = 1 or 2. 
+    pushToGroupAuto : function(items, groups, recognizeFunction, recognizeGroup){//自动分组。 items是将分到一起的组合。items.length = 1 or 2. 
     
         recognizeFunction = recognizeFunction || function(){}
     
-        var atGroups = groups.filter(group=>group.find(
-            item => items[0] == item || recognizeFunction(item, items[0]) || items[1] == item || items[1] && recognizeFunction(item, items[1])
         
-        )) 
+        if(recognizeGroup){ //有更复杂的识别处理,直接传递整个组
+            var atGroups = groups.filter(group=>recognizeGroup(group, items))
+                 
+        }else{
+            var atGroups = groups.filter(group=>group.find(
+                item => items[0] == item || recognizeFunction(item, items[0]) || items[1] == item || items[1] && recognizeFunction(item, items[1])
+            )) 
+        
+        }
+        
+        
         if(atGroups.length){//在不同组
             //因为items是一组的,所以先都放入组1
             items.forEach(item=> {if(!atGroups[0].includes(item)) atGroups[0].push(item);})

+ 2 - 0
src/custom/utils/SplitScreen.js

@@ -15,6 +15,7 @@ class SplitScreen extends THREE.EventDispatcher{
         这两个参数的主要目的是为了getPosOutOfModel,以及rotateSideCamera时保持相对位置
     */
     splitStart(cameraProps){ 
+        this.splited = true
         let viewports = []
       
         let subViewports = [viewer.mainViewport]
@@ -61,6 +62,7 @@ class SplitScreen extends THREE.EventDispatcher{
     
     
     unSplit(){
+        this.splited = false
         this.unfocusViewport()
         viewer.inputHandler.hoverViewport = null //清空
         viewer.viewports = [viewer.mainViewport] 

+ 1 - 1
src/custom/utils/SplitScreen4Views.js

@@ -255,7 +255,7 @@ SplitScreen4Views.recover = function(){
 
 SplitScreen4Views.updateMapViewerBG = function(){
     let mapViewport = viewer.mapViewer.viewports[0]
-    if( this.floorplanEnabled ||  this.mapEnabled){
+    if(this.splited && (this.floorplanEnabled || this.mapEnabled)){
         mapViewport.background = 'overlayColor'
         mapViewport.backgroundColor = new THREE.Color(0,0,0)
         mapViewport.backgroundOpacity = 0.5; 

+ 3 - 3
src/custom/utils/UnitConvert.js

@@ -270,8 +270,8 @@ class UoMService{
         return  this.convert(t, n, precision, r, minFactor)
     }
     
-    convert(number, domain, precision = 2, system, minFactor, ifEighths = !1, ifRestrictFactor) { 
-        if (!number) return "";
+    convert(number, domain, precision = 2, system, minFactor, ifEighths = !1, ifRestrictFactor ) { 
+        //if (!number) return "";
         var s = this.getMostRelevantMeasurement(domain, system || this.UnitService.currentSystem, number, minFactor, ifRestrictFactor);
         return this.getFormattedMeasurementString(s[0], s[1], precision, ifEighths)
     }
@@ -314,7 +314,7 @@ class UoMService{
           , i = Math.floor(n / 8)
           , r = Math.floor(i / FEET_TO_INCHES_FACTOR)
           , o = i - r * FEET_TO_INCHES_FACTOR
-          , a = EIGHTHS_SYMBOLS[n % 8]
+          , a = EIGHTHS_SYMBOLS[Math.abs(n % 8)]
           , s = 0 === o && "" !== a ? "" : o;
           
         "" !== s && "" !== a && (a = " " + a)   

+ 103 - 48
src/custom/viewer/ViewerNew.js

@@ -583,6 +583,9 @@ export class Viewer extends ViewerBase{
             //-----------
             
             
+            this.modules.volumeComputer && this.modules.volumeComputer.init()
+            
+            
 		}catch(e){
 			this.onCrash(e);
 		}
@@ -2813,8 +2816,8 @@ export class Viewer extends ViewerBase{
             let clipBoxes_in = clipBoxes.filter(e=>e.box.clipTask == ClipTask.SHOW_INSIDE && !e.box.highlight)
             let clipBoxes_out = clipBoxes.filter(e=>e.box.clipTask == ClipTask.SHOW_OUTSIDE && !e.box.highlight)
             let highlightBoxes = clipBoxes.filter(e=>e.box.highlight )
-			let prismPolygons = this.modules.volumeComputer && this.modules.volumeComputer.entered ? viewer.scene.measurements.filter(e=>(e.measureType == 'MulDistance Ring') && !e.isNew) : []
-            
+			//let prismPolygons = this.modules.volumeComputer && this.modules.volumeComputer.entered ? viewer.scene.measurements.filter(e=>(e.measureType == 'MulDistance Ring') && !e.isNew) : []
+			let prismPolygons = this.modules.volumeComputer ? this.modules.volumeComputer.prisms.filter(e=>!e.isNew && e.visible) : []
             
             // set clip volumes in material
 			for(let pointcloud of visiblePointClouds){
@@ -3394,9 +3397,9 @@ export class Viewer extends ViewerBase{
      
     renderOverlay1(params){ 
         let camera = params.camera ? params.camera : this.scene.getActiveCamera();
-        
+        let renderer = params.renderer || this.renderer
         this.reticule.updateAtViewports(params.viewport)
-        this.renderer.setRenderTarget(params.target||null)
+        renderer.setRenderTarget(params.target||null)
         
          //为什么要在点云之后渲染,否则透明失效 、 会被点云覆盖 
         let cameraLayers
@@ -3428,7 +3431,7 @@ export class Viewer extends ViewerBase{
             }
             
             viewer.dispatchEvent({type: "render.begin2" , name:'scene', viewport:params.viewport  })
-            this.renderer.render(this.scene.scene, camera);  
+            renderer.render(this.scene.scene, camera);  
              
             if('renderBeforeCloud' in params){
                 this.scene.scene.traverse((object)=>{
@@ -3447,26 +3450,26 @@ export class Viewer extends ViewerBase{
     
     
     renderOverlay2(params){
-        
+        let renderer = params.renderer || this.renderer
         let camera = params.camera ? params.camera : this.scene.getActiveCamera();
         //清除深度 !!!!
-        this.renderer.clearDepth(); 
+        renderer.clearDepth(); 
  
         if(!params.magnifier){ 
             //测量线 
-            this.dispatchEvent({type: "render.pass.perspective_overlay", camera, screenshot:params.screenshot,viewport:params.viewport});
+            this.dispatchEvent({type: "render.pass.perspective_overlay", camera, screenshot:params.screenshot,viewport:params.viewport, renderer});
             
             if(!params.screenshot && params.viewport.name != "mapViewport" ){
                 Potree.Utils.setCameraLayers(camera, ['magnifier']) //magnifier 遮住测量线 
-                this.renderer.render(this.scene.scene, camera);
+                renderer.render(this.scene.scene, camera);
             }
         } 
         
         if(params.viewport.name != "mapViewport" ) {
             Potree.Utils.setCameraLayers(camera, ['volume','transformationTool'])  
             //viewer.dispatchEvent({type: "render.begin2" , name:'clip&trans',viewport:params.viewport  })
-            this.renderer.render(this.clippingTool.sceneVolume, camera);  //official 可以删
-            this.renderer.render(this.transformationTool.scene, camera);
+            renderer.render(this.clippingTool.sceneVolume, camera);  //official 可以删
+            renderer.render(this.transformationTool.scene, camera);
         }
     
     
@@ -3510,7 +3513,7 @@ export class Viewer extends ViewerBase{
    
         let s = SiteModel.editing && SiteModel.selected && (SiteModel.selected.buildType == 'room' || SiteModel.selected.buildType == 'floor') //空间模型的房间选中材质是需要depth的,这时候需要绘制两次点云
          
-        Potree.settings.pointEnableRT = !this.screenshoting && (this.scene.measurements.length > 0 || s )
+        Potree.settings.pointEnableRT = !this.screenshoting && (this.scene.measurements.filter(e=>e.visible).length > 0 || s )
         
          
         if(vrActive){
@@ -3547,7 +3550,7 @@ export class Viewer extends ViewerBase{
         let finishDeferred = info.finishDeferred || $.Deferred();
  
         let viewerMaster = info.map ? this.mapViewer : this; //截图主体
-        let useMap = info.type == 'measure' || info.map || info.type == 'prism2d-all'
+        let useMap = info.map || info.type == 'measure' || info.type.includes('prism2d')
         
         
         if(Potree.settings.displayMode == 'showPanos' && viewer.scene.view.isFlying('pos')){//如果在飞,飞完再截图
@@ -3566,10 +3569,10 @@ export class Viewer extends ViewerBase{
         console.log('startScreenshot: '+sid)
         
         let updateCamera = ()=>{ 
-            this.viewports.forEach(e=>{
+            viewports.forEach(e=>{
                 e.view.applyToCamera(e.camera) //因为fly时只更新了view所以要强制更新下camera
                  
-                this.dispatchEvent({  //update map  and sprite
+                this.dispatchEvent({  //update map  and sprite,  mapChanged
                     type: "camera_changed", 
                     camera: e.camera,
                     viewport : e,
@@ -3592,15 +3595,21 @@ export class Viewer extends ViewerBase{
             }else{ 
                 
                 //直接渲染 会改变canvas大小
-                let canvas = this.renderArea.getElementsByTagName('canvas')[0]  
+                let canvas = viewerMaster.renderArea.getElementsByTagName('canvas')[0]  
                 //canvas.width = width, canvas.height = height //不需要改canvas大小, 只需要 this.renderer.setSize(width, height ); 前面updateScreenSize已经执行
-                this.render({  screenshot : true,   width , height,   resize :true  }); //需要resize
-                var dataUrl = canvas.toDataURL('image/jpeg',compressRatio) 
+                viewerMaster.render({  screenshot : true,   width , height,   resize :true  }); //需要resize
+                
+                /* if(info.type.includes('prism2d')){//o.map要为true
+                    viewer.dispatchEvent({type:'resize', viewport:viewer.mapViewer.viewports[0]}) //借用viewer通知lineMaterial resize
+                    viewerMaster.renderOverlay()
+                } */
+                
+                var dataUrl = canvas.toDataURL('image/png',compressRatio) 
             }
             
             
             if(!Potree.settings.isOfficial){
-                Common.downloadFile(dataUrl, 'screenshot.jpg') 
+                Common.downloadFile(dataUrl, 'screenshot.png') 
             } 
             
             
@@ -3612,11 +3621,10 @@ export class Viewer extends ViewerBase{
                     viewport.left = old.left; viewport.bottom = old.bottom;
                     viewport.width = old.width; viewport.height = old.height
                     viewport.view.copy(old.view) 
-                    viewport.view.applyToCamera(viewport.camera);  
-                     
+                    //viewport.view.applyToCamera(viewport.camera);  
                 }) 
                 
-                viewer.updateScreenSize({forceUpdateSize:true})//更新像素
+                viewerMaster.updateScreenSize({forceUpdateSize:true})//更新像素
                 
                 /* oldStates.viewports.forEach(old=>{//恢复相机
                     var viewport = [mapViewport, mainViewport].find(v=>v.name == old.name);
@@ -3631,7 +3639,7 @@ export class Viewer extends ViewerBase{
                 finishDeferred.resolve({dataUrl, pose})
                
                
-                setTimeout(()=>{
+                info.map || setTimeout(()=>{
                     if(!this.screenshoting){
                         //Potree.settings.pointNoLimit = false  
                         Potree.settings.pointDensity = 'high'
@@ -3651,29 +3659,39 @@ export class Viewer extends ViewerBase{
                 
                  
                 
-                if(info.type == 'measure'){
+                if(info.type == 'measure' || info.type.includes('prism2d')){
                     this.modules.SiteModel.pauseUpdateEntity = false
                     this.focusDatasets = null
                     this.scene.measurements.forEach(e=>Potree.Utils.updateVisible(e, 'screenshot',true))
-                    info.measurement.setSelected(false, 'screenshot')
+                    info.type == 'measure' && info.measurement.setSelected(false, 'screenshot')
+                }
+                
+                if(info.type.includes('prism2d')){
+                    //viewer.mapViewer.transparentBG = false;
+                    this.backgroundOpacity = oldStates.bgOpacity; 
+                    (info.prisms || [info.prism]).forEach(prism=>{
+                        prism.changeStyleForScreenshot(false)
+                    })  
                 }
+                
+                
+                
                 this.images360.panos.forEach(pano=>{
                     Potree.Utils.updateVisible(pano, 'screenshot', true)
                 })    
                 Potree.Utils.updateVisible(this.reticule, 'screenshot', true)
                  
-            
+                
+                 
                 
                 if(useMap){
                     Potree.Utils.updateVisible(this.mapViewer.cursor, 'screenshot', true)
                     
                     
-                    if(oldStates.attachedToViewer != this.mapViewer.attachedToViewer){
-                        if(info.type == 'measure'){
-                            this.mapViewer.attachToMainViewer(false )   
-                        } 
+                    if(oldStates.attachedToViewer != this.mapViewer.attachedToViewer){ 
+                        this.mapViewer.attachToMainViewer(!!oldStates.attachedToViewer )   
                     }
-                    if(this.mapViewer.splitDir != oldStates.oldSplitDir){
+                    if(oldStates.attachedToViewer && this.mapViewer.splitDir != oldStates.oldSplitDir){
                         this.mapViewer.changeSplitScreenDir(oldStates.oldSplitDir)
                     }
                     
@@ -3683,7 +3701,7 @@ export class Viewer extends ViewerBase{
                     mapViewport.camera.updateProjectionMatrix()  
                 } 
                       
-                  
+                Potree.Utils.updateVisible(viewer.mapViewer.mapLayer.sceneGroup, 'screenshot-prism', true) 
                 
                 
                 let recover = ()=>{ 
@@ -3759,9 +3777,7 @@ export class Viewer extends ViewerBase{
                 //console.log(levels)
                 let actMaxLevel = Math.max.apply(null, levels) //实际加载到的最高的node level
                 //console.warn('decreaseLevel, 新maxLevel', actMaxLevel - 1, '原maxlevel', viewer.scene.pointclouds[0].maxLevel, 'numVisiblePoints', Potree.numVisiblePoints) 
-                /* viewer.scene.pointclouds[0].maxLevel = actMaxLevel - 1
-                viewer.scene.pointclouds[0].material.oldSize_ = viewer.scene.pointclouds[0].material.size
-                viewer.scene.pointclouds[0].material.size *= 1.5 */
+                 
             }
             if(Potree.settings.displayMode == 'showPointCloud'){
                 viewer.updateScreenSize({forceUpdateSize:true, width, height, forTarget:info.useRenderTarget})//需要先setSize才能加载范围内的点云
@@ -3868,20 +3884,40 @@ export class Viewer extends ViewerBase{
                 
             })
         }else if(info.type.includes('prism2d')){
-            let points = [], prisms = info.type == 'prism2d-all' ? this.modules.volumeComputer.prisms : [info.prism]
+              
+            let points = [], prisms = info.type == 'prism2d-all' ? info.prisms: [info.prism]
             
-            viewer.mapViewer.updateScreenSize({forceUpdateSize:true, width, height, forTarget:info.useRenderTarget}) //更新viewports相机透视 使focusOnObject在此窗口大小下
-             
-            prisms.forEach(e=>points.push(...e.points)) 
+            this.mapViewer.attachToMainViewer(true, 'screenshot', 1 ,  {/* dir:'leftRight' */} ) 
+            
+            viewer.updateScreenSize({forceUpdateSize:true, width, height, forTarget:info.useRenderTarget}) //更新viewports相机透视 使focusOnObject在此窗口大小下
              
-            let {promise} = this.focusOnObject({points}, 'prisms2d', 0, { 
-                minMapWidth: 0.2  , onlyMap:true,  focusBoundCenter:true
+            prisms.forEach(prism=>{
+                points.push(...prism.points) 
+                prism.changeStyleForScreenshot(true, {hideLabel: info.type != 'prism2d-all',  showName: info.type == 'prism2d-all' })
+                   
             }) 
+            
+            let {promise} = this.focusOnObject({points}, 'prisms2d', 0, { 
+                minMapWidth: 0.5  , onlyMap:true,  focusBoundCenter:true, boundExpandRatio:1.4
+            })  
+            
+            oldStates.bgOpacity = this.backgroundOpacity
+            this.backgroundOpacity = 0
+                 
             promise.done(()=>{
+                updateCamera() 
+                 
                 if(info.type == 'prism2d-all'){//全部 带平面图   
                     focusDatasets(prisms) //更新平面图  可能有漏洞,当不在任何一个数据集内的话?
                     this.mapViewer.waitLoadDone(screenshot.bind(this))//等待地图所有加载完
                 }else{//单个
+                 
+                    this.scene.measurements.forEach(e=>Potree.Utils.updateVisible(e,'screenshot', e == info.prism)  )
+                    //info.prism.setSelected(true, 'screenshot')
+                    //viewer.mapViewer.transparentBG = true
+                
+                    Potree.Utils.updateVisible(viewer.mapViewer.mapLayer.sceneGroup, 'screenshot-prism', false)
+
                     screenshot()
                 }
             })
@@ -3915,11 +3951,9 @@ export class Viewer extends ViewerBase{
         let camera = o.endCamera || viewer.scene.getActiveCamera()
         let cameraPos = camera.position.clone()
         let boundSize   
-        /* if(camera.type == 'OrthographicCamera'){
-            return console.error('focusOnObject暂不支持OrthographicCamera。因情况复杂,请视情况使用splitScreenTool.viewportFitBound')
-        } */
         
-        let moveMap = ()=>{
+        
+        let moveMap = (done)=>{
             if(this.mapViewer){ 
                 //console.log('mapFocusOn: '+target.toArray())
                 const minMapWidth = o.minMapWidth || 2 //截图的时候要显示的地图范围较大,为了显示出地区名字
@@ -3940,15 +3974,18 @@ export class Viewer extends ViewerBase{
                 }
                 let boundSizeOri = boundOri.getSize(new THREE.Vector3)
                  
-                let boundSizeMap = boundSizeOri.clone().multiplyScalar(2)
+                let boundSizeMap = boundSizeOri.clone().multiplyScalar(o.boundExpandRatio || 1.5)
                 boundSizeMap.x = Math.max(minBound.x, boundSizeMap.x )
                 boundSizeMap.y = Math.max(minBound.y, boundSizeMap.y )
-                this.mapViewer.moveTo(target.clone(), boundSizeMap, duration)
+                this.mapViewer.moveTo(target.clone(), boundSizeMap, duration, o.margin, null,  done)
             }
         }
         
         if(o.onlyMap){
-            return moveMap()
+            moveMap(()=>{
+                deferred.resolve()
+            })  
+            return {promise:deferred.promise()}
         }
         
         let getPosWithFullBound = (points, boundingBox, target, cameraPos  )=>{//使boundingBox差不多占满屏幕时的相机到target的距离
@@ -4454,6 +4491,24 @@ export class Viewer extends ViewerBase{
         
     }
 
+
+    findClosestDatasetOnMap(position){//寻找当前平面图上离某点最近的数据集
+        let pointclouds = viewer.scene.pointclouds.filter(e=>e.visible);
+         
+        const addScore = viewer.bound.boundSize.length()
+        let r = Potree.Common.sortByScore(pointclouds, [], [(e)=>{//pos2d和bound2d距离排序
+            let pos3d = position.clone().setZ(e.panosBound ? e.panosBound.center.z : (e.bound.min.z+e.bound.max.z)/2)
+            return - (e.panosBound ? e.panosBound.bounding : e.bound).distanceToPoint(pos3d)
+        },(e)=>{//最有可能的是地图上显示的平面图
+            return e in viewer.fpVisiDatasets ?  addScore : 0 
+        }]);
+        return r[0] && r[0].item
+
+    }
+    
+
+
+
  
     addTimeMark(name, type){
         let record = Potree.timeCollect[name] 

+ 3 - 1
src/custom/viewer/map/Map.js

@@ -69,7 +69,9 @@ export class MapLayer extends THREE.EventDispatcher{ // 包括了 MapLayerBase S
         
 
         //map.setEnable(false)
-          
+        this.sceneGroup.addEventListener('isVisible',()=>{
+            this.viewer.mapChanged = true
+        })
        
     }
     

+ 25 - 12
src/custom/viewer/map/MapViewer.js

@@ -41,7 +41,7 @@ export class MapViewer extends ViewerBase{
     constructor(dom){
         super(dom, {
             clearColor: Potree.config.mapBG,
-            name: 'mapViewer'
+            name: 'mapViewer',  //antialias:true
         })
         this.visible = true
         this.initScene()
@@ -50,7 +50,7 @@ export class MapViewer extends ViewerBase{
         this.mapLayer = new MapLayer(this, this.viewports[0])
         this.scene.add(this.mapLayer.sceneGroup)
         this.mapLayer.sceneGroup.position.setZ(Potree.config.map.mapHeight)
-        this.mapRatio = 0.5
+        this.mapRatio = 0.5 
         this.splitDir = 'leftRight'
         
         
@@ -470,9 +470,9 @@ export class MapViewer extends ViewerBase{
         this.moveTo(center, size, 200 ) //给duration是为了顺应视口大小改变,缓冲
     }
     
-    moveTo(endPosition, boundSize, duration=0, margin, easeName ){//前两个参数有xy即可
+    moveTo(endPosition, boundSize, duration=0, margin, easeName, callback ){//前两个参数有xy即可
         endPosition = new THREE.Vector3(endPosition.x,endPosition.y,Potree.config.map.cameraHeight)
-        this.view.moveOrthoCamera(this.viewports[0],  {endPosition, boundSize, margin},   duration,  easeName)
+        this.view.moveOrthoCamera(this.viewports[0],  {endPosition, boundSize, margin, callback},   duration,  easeName)
         
        
         
@@ -626,7 +626,7 @@ export class MapViewer extends ViewerBase{
     }
     
     changeSplitScreenDir(dir, mapRatio){//左右 | 上下
-        //if(!dir || dir == this.dir)return
+        //if(!dir || dir == this.dir)return 
         if(dir )this.splitDir = dir
         this.updateSplitSize(mapRatio)
         /* if(this.attachedToViewer){ //如果已经分屏了,中途修改方向的话……
@@ -709,8 +709,16 @@ export class MapViewer extends ViewerBase{
         return true
     }
     
-    
-    
+    clear(params){  
+        if(this.transparentBG){
+            this.renderer.setClearColor( 0x000000, 0 );
+        }else{
+            this.renderer.setClearColor( Potree.config.mapBG, 1 );
+        }
+        
+        (params.renderer || this.renderer).clear()
+    }  
+ 
     
     //拆成两次渲染,一个地图一个其他物体,且地图渲染后保存在buffer中,只有当地图变化后才重渲染。 
     render(params={}){ 
@@ -723,8 +731,9 @@ export class MapViewer extends ViewerBase{
          
         if(this.mapChanged){  //渲染地图背景
             renderer.setRenderTarget(this.copyBuffer) 
-            params.clear ? params.clear() : renderer.clear(); 
+            params.clear ? params.clear(params) : this.clear(params); 
             
+           
             if(this.mapGradientBG){//渲染背景
                 viewer.scene.cameraBG.layers.set(Potree.config.renderLayers.bg);
                 renderer.render(viewer.scene.scene, viewer.scene.cameraBG);
@@ -732,13 +741,13 @@ export class MapViewer extends ViewerBase{
             Potree.Utils.setCameraLayers(this.camera, ['map'])
             renderer.render(this.scene, this.camera);
             
-            params.renderBG && params.renderBG(this.viewports[0])
+            params.renderBG && params.renderBG(this.viewports[0]) 
             
-            this.mapChanged = false
+            this.mapChanged = false 
             renderer.setRenderTarget(params.target||null) 
         }
         
-        params.clear ? params.clear() : renderer.clear(); 
+        params.clear ? params.clear(params) : this.clear(params); 
         this.copyPass.render(null,null, null,renderer, params.target||null, this.copyBuffer) //拷贝地图背景
         renderer.clearDepth(); //防止地图遮挡其他物体
         
@@ -760,7 +769,11 @@ export class MapViewer extends ViewerBase{
         return true      
     }
 
-    
+    renderOverlay(){//偶尔需要绘制测量线
+        viewer.renderOverlay({
+            camera: this.camera,  viewport:this.viewports[0], renderer:this.renderer 
+        })
+    }
     
     
      

+ 1 - 4
src/materials/ExtendPointCloudMaterial.js

@@ -353,12 +353,9 @@ export class ExtendPointCloudMaterial extends PointCloudMaterial {
             
             let pointIndex = 0
             for(let i=0;i<prismPolygons.length;i++ ){ 
-                let bound = Potree.math.getBound(prismPolygons[i].points)
-                prismPolygons[i].prismBound = bound
+                let bound = prismPolygons[i].prismBound 
                 let z = prismPolygons[i].horizonZ 
                 //z = Potree.browser.urlHasValue('zmin',true) ||  zs[0]  
-                bound.min.z = /* z - 2// */viewer.bound.boundingBox.min.z
-                bound.max.z = /* z + 4// */viewer.bound.boundingBox.max.z
                  
                 this.uniforms.prismList.value.set([bound.min.z, z, bound.max.z, bound.min.x, bound.max.x, bound.min.y, bound.max.y,  prismPolygons[i].points.length ],9*i)
                 for(let j=0;j<prismPolygons[i].points.length;j++){

+ 1 - 1
src/materials/shaders/pointcloud_new.vs

@@ -840,7 +840,7 @@ bool insideBox(mat4 clipBox, vec4 worldPos){//add
         int j=pointCount-1;
         
         for(int i=0; i<prism_maxPointsCount; i++){
-            if(i>pointCount)break;
+            if(i>=pointCount)break;
             float xi = prismPoints[i+pointIndexStart].x,  yi = prismPoints[i+pointIndexStart].y, xj = prismPoints[j+pointIndexStart].x, yj = prismPoints[j+pointIndexStart].y;
 
             if(((yi > worldPos.y) != (yj > worldPos.y)) && (worldPos.x < (xj - xi) * (worldPos.y - yi) / (yj - yi) + xi)){