Sfoglia il codice sorgente

粒子添加 火场

xzw 3 anni fa
parent
commit
10d878eb9a
37 ha cambiato i file con 1660 aggiunte e 1055 eliminazioni
  1. 13 2
      libs/three.js/build/three.module.js
  2. 59 3
      note笔记笔记笔记.txt
  3. 10 1
      src/EventDispatcher.js
  4. 11 6
      src/PointCloudOctree.js
  5. 24 13
      src/Potree.js
  6. 3 1
      src/Potree_update_visibility.js
  7. 149 336
      src/modules/CameraAnimation/CameraAnimation.js
  8. 75 86
      src/modules/Images360/Images360.js
  9. 8 9
      src/modules/Images360/Panorama.js
  10. 2 1
      src/modules/clipModel/Clip.js
  11. 1 2
      src/modules/datasetAlignment/Alignment.js
  12. 15 1
      src/modules/siteModel/SiteModel.js
  13. 3 3
      src/navigation/InputHandler.js
  14. 22 7
      src/objects/Label.js
  15. 37 12
      src/objects/Magnifier.js
  16. 22 20
      src/objects/Reticule.js
  17. 26 16
      src/objects/Sprite.js
  18. 5 0
      src/objects/TextSprite.js
  19. 23 16
      src/objects/fireParticle/explode/ExplodeParticle.js
  20. 123 79
      src/objects/fireParticle/fire/FireParticle.js
  21. 24 3
      src/objects/fireParticle/fire/shader.js
  22. 134 65
      src/objects/fireParticle/smoke/SmokeParticle.js
  23. 257 0
      src/objects/tool/CurveCtrl.js
  24. 11 29
      src/objects/tool/Measure.js
  25. 2 2
      src/objects/tool/ScreenBoxSelectTool.js
  26. 16 9
      src/objects/tool/ctrlPolygon.js
  27. 2 2
      src/settings.js
  28. 54 143
      src/start.js
  29. 24 5
      src/utils.js
  30. 90 81
      src/utils/DrawUtil.js
  31. 48 40
      src/utils/SplitScreen.js
  32. 1 6
      src/utils/math.js
  33. 17 19
      src/viewer/PropertyPanels/CameraAnimationPanel.js
  34. 11 3
      src/viewer/map/Map.js
  35. 22 18
      src/viewer/map/MapViewer.js
  36. 267 16
      src/viewer/viewer.js
  37. 49 0
      改bug的历史.txt

+ 13 - 2
libs/three.js/build/three.module.js

@@ -258,7 +258,18 @@ Object.assign( EventDispatcher.prototype, {
 		}
 
 	},
-
+    removeEventListeners(type){//add
+		if(this._listeners[type] !== undefined){
+			delete this._listeners[type];
+		}
+	} ,
+    removeAllListeners(){ //add
+        this._listeners = {};
+        
+    },
+    
+    
+    
 	dispatchEvent: function ( event ) {
 
 		if ( this._listeners === undefined ) return;
@@ -282,7 +293,7 @@ Object.assign( EventDispatcher.prototype, {
 		}
 
 	}
-
+    
 } );
 
 const _lut = [];

+ 59 - 3
note笔记笔记笔记.txt

@@ -28,6 +28,13 @@ t-GusppsiKEC 字节跳动楼外场景
 t-YLZ5XAALl7 燃气管线街景
 SS-t-P6zBR73Gke 燃气站
 t-QaHxu5Nmn3 一楼门口
+t-5HxBflA 梁启超故居
+
+
+
+
+
+
 	--多楼层漫游点:
 
 
@@ -91,6 +98,10 @@ moveSpeed 、 地图的自适应缩放
 地理位置修改了的话,没有绑定到数据集上的测量线怎么办? 要不还是默认放第一个数据集?
 
 
+ 
+clip没写完。如果按照房间显示点云的话。
+ 
+ 
 
 ---------
 Bug	|
@@ -187,11 +198,56 @@ cursor总感觉应该打开。 但是会比较乱,而且用reticule也可以
 
 --------------------
  
-出现过mainViewer中的reticule位置改变特别慢
+clip时根据显示的范围来显示列表
+
+
+
+ this.setProjectedPanos({  在点云模式禁止,切换全景转动后会变白
+
+
+ this.on('updateNodeMaxLevel',(pointcloud,nodeMaxLevel)  多个数据集的话,万一node level比较高的在远方还没加载怎么办?
+
+
+消防 https://78h5qu.axshare.com/#id=k94ltt&p=%E6%B7%BB%E5%8A%A0%E8%A7%86%E9%A2%91&g=1
+
+
+
+route反向后datasetId没反向。。。还有如果在地图上没有datasetID
 
 
+加载平面图。
+根据楼层加载平面图,且只展示当前楼层的漫游点。漫游点怎么选取,会不会不小心到其他楼?marker全部展示会很多天花板都有
+
  
  
-测试测量的截图有没问题
+数据集右上方的改彩色  地理注册
+
+
+
+火场轨迹和宽度
+
+
+removeMarker 等 dispose时, 要removeAllListeners 还有所有其他的侦听
+还有不可见时 比如RouteGuider
+
+
+
+把dispatchEvent简单写下,即使第一个就传type也能运行
+
+
+
+
+给你整理下现在三种火的类型参数:
+1 火焰:
+	颜色、 直径(宽度)、 高度、  密度百分比
+2 烟:(随着火添加)
+	颜色(黑色程度)、 直径 、速度(能影响高度)、 密度百分比
+3 爆炸:(另外添加)
+	 间隔时间、  直径、 密度百分比
+
+
+
+
+
+端点拖动时最好能切换成着附在点云上。或者在有点云时着附在点云上
 
-  

+ 10 - 1
src/EventDispatcher.js

@@ -84,6 +84,9 @@ export class EventDispatcher{
 			delete this._listeners[type];
 		}
 	};
+    
+    
+    
 
 	dispatchEvent(event){
 
@@ -108,7 +111,7 @@ export class EventDispatcher{
     emit(type){ 
         this.dispatchEvent({type, arguments: Array.from(arguments).slice(1, arguments.length) })
     }
-    on(type, fun){
+    on(type, fun){ //off怎么写?
         this.addEventListener(type,(ev)=>{
             fun.apply(this, ev.arguments)
         })
@@ -122,6 +125,12 @@ export class EventDispatcher{
         return callback.listener = fun,
             this.on(type, callback),
             this
+    } 
+    
+    removeAllListeners(){
+        
+        this._listeners = {};
+        
     }
      
 }

+ 11 - 6
src/PointCloudOctree.js

@@ -1383,7 +1383,7 @@ export class PointCloudOctree extends PointCloudTree {
 	 * TODO: only draw pixels that are actually read with readPixels().
 	 *
 	 */
-	pick(viewer, camera, ray, params = {}){
+	pick(viewer, viewport, camera, ray, params = {}){
 
 		let renderer = viewer.renderer;
 		let pRenderer = viewer.pRenderer;
@@ -1391,11 +1391,15 @@ export class PointCloudOctree extends PointCloudTree {
 		performance.mark("pick-start");
 
 		let getVal = (a, b) => a !== undefined ? a : b;
-
-		let pickWindowSize = getVal(params.pickWindowSize,  5  /* 65 */);  //拾取像素边长,越小越精准,但点云稀疏的话可能容易出现识别不到的情况
+        
+        
+        let pickWindowSize_ = THREE.Math.clamp( Math.round((1.1-this.maxLevel/this.nodeMaxLevel)*80),  5, 100)
+        
+		let pickWindowSize = getVal(params.pickWindowSize, pickWindowSize_    ); /* 65 */ //拾取像素边长,越小越精准,但点云稀疏的话可能容易出现识别不到的情况。 另外左下侧会有缝隙无法识别到,缝隙大小和这个值有关
+ 
 		let pickOutsideClipRegion = getVal(params.pickOutsideClipRegion, false);
 
-		let size = renderer.getSize(new THREE.Vector2());
+		let size = viewport ? viewport.resolution : renderer.getSize(new THREE.Vector2());
 
 		let width = Math.ceil(getVal(params.width, size.width)); //renderTarget大小。影响识别精度  
 		let height = Math.ceil(getVal(params.height, size.height));
@@ -1609,8 +1613,9 @@ export class PointCloudOctree extends PointCloudTree {
 					let z = attribute.array[3 * hit.pIndex + 2];
 
 					let position = new THREE.Vector3(x, y, z);
-					position.applyMatrix4(pc.matrixWorld);
-
+                    
+					position.applyMatrix4( pc.matrixWorld );
+                    
 					point[attributeName] = position;
 				} else if (attributeName === 'indices') {
 

+ 24 - 13
src/Potree.js

@@ -172,32 +172,43 @@ export async function loadDatasets(callback){//之后直接把path写进来
     
 }
 export async function loadMapEntity(){
-    var path 
-    let callback = (data)=>{
-        var map = viewer.mapViewer.mapLayer.maps.find(e => e.name == 'floorplan')
+    if((!Potree.settings.floorplanType || !Potree.settings.floorplanEnable) && Potree.fileServer)return /* 等待平面图类型定义好会加载 */
+    let pointcloudNum = viewer.scene.pointclouds.length
+    let loaded = 0
+    
+    let callback = (datasetId, data )=>{
+        var map = viewer.mapViewer.mapLayer.maps.find(e => e.name == 'floorplan_'+ datasetId)
         if(map){
             viewer.mapViewer.mapLayer.removeMap(map)
         }else{
             
         }
         
-        viewer.mapViewer.mapLayer.addMapEntity(data.data || data )
-    }
-    if(Potree.fileServer){
-        if(!Potree.settings.floorplanType || !Potree.settings.floorplanEnable)return /* 等待平面图类型定义好会加载 */
-        path = `/laser/tiledMap/${Potree.settings.number}/tiledMap/${Potree.settings.floorplanType}/${Potree.settings.originDatasetId}` 
-    }else{
-        path = `https://${Potree.config.urls.prefix2}/indoor/${Potree.settings.number}/api/tiled_maps`
+        var map = viewer.mapViewer.mapLayer.addMapEntity(data.data || data )
+        map.name += "_"+ datasetId
+        loaded ++;
+        
         
     }
-    return loadFile(path, callback)
+    
+    viewer.scene.pointclouds.forEach(e=>{
+        var path 
+        if(Potree.fileServer){ 
+            path = `/laser/tiledMap/${Potree.settings.number}/tiledMap/${Potree.settings.floorplanType}/${e.dataset_id}` 
+        }else{
+            path = `https://${Potree.config.urls.prefix2}/indoor/${Potree.settings.number}/api/tiled_maps`
+            
+        }
+        return loadFile(path, callback.bind(this, e.dataset_id)  )
+    })
+    
      
     
 }
  
-export async function loadPanos(center, callback){
+export async function loadPanos(datasetId, callback){
     var path 
-    let query = `?datasetId=${Potree.settings.originDatasetId}`                  //`?lat=${center.lat}&lon=${center.lon}&radius=200000`
+    let query = `?datasetId=${datasetId}`                  //`?lat=${center.lat}&lon=${center.lon}&radius=200000`
     if(Potree.fileServer){
         path = `/laser/filter/${Potree.settings.number}/query` + query
     }else{ 

+ 3 - 1
src/Potree_update_visibility.js

@@ -322,8 +322,10 @@ export function updateVisibility(pointclouds, camera, areaSize){
 			let transformVersion = pointcloudTransformVersion.get(pointcloud);
 			if(node._transformVersion !== transformVersion.number){
 				node.sceneNode.updateMatrix();
+				//node.sceneNode.matrixWorld.multiplyMatrices(pointcloud.matrixWorld, node.sceneNode.matrix);	
 				node.sceneNode.matrixWorld.multiplyMatrices(pointcloud.matrixWorld, node.sceneNode.matrix);	
-				node._transformVersion = transformVersion.number;
+				
+                node._transformVersion = transformVersion.number;
                                
 			}
 

+ 149 - 336
src/modules/CameraAnimation/CameraAnimation.js

@@ -2,22 +2,41 @@
 import * as THREE from "../../../libs/three.js/build/three.module.js";
 import { EventDispatcher } from "../../EventDispatcher.js";
 import { Utils } from "../../utils.js";
-import {Line2} from "../../../libs/three.js/lines/Line2.js";
-import {LineGeometry} from "../../../libs/three.js/lines/LineGeometry.js";
-import {LineMaterial} from "../../../libs/three.js/lines/LineMaterial.js";
+ 
+import {LineDraw} from "../../utils/DrawUtil"; 
+import CurveCtrl from  "../../objects/tool/CurveCtrl";
+ 
 
+ 
 
-class ControlPoint{
-
-	constructor(){
-		this.position = new THREE.Vector3(0, 0, 0);
-		this.target = new THREE.Vector3(0, 0, 0);
-		this.positionHandle = null;
-		this.targetHandle = null;
-	}
-
-};
+const colors = {
+    position: 'red', 
+    target : 'blue'
+}
+ 
+
+let lineMats
+const getLineMat = function(name){
+    if(!lineMats){
+        lineMats = {
+            position: LineDraw.createFatLineMat({
+                color: colors.position,  
+                lineWidth: 3   
+            }),
+            target : LineDraw.createFatLineMat({
+                color: colors.target,  
+                lineWidth: 3  
+            }),
+            frustum:  LineDraw.createFatLineMat({
+                color: colors.position,  
+                lineWidth: 2   
+            }),
+        }
+    }
+    return lineMats[name]
+}
 
+ 
 
 
 export class CameraAnimation extends EventDispatcher{
@@ -29,7 +48,7 @@ export class CameraAnimation extends EventDispatcher{
 
 		this.selectedElement = null;
 
-		this.controlPoints = [];
+		//this.controlPoints = [];
 
 		this.uuid = THREE.Math.generateUUID();
 
@@ -47,8 +66,19 @@ export class CameraAnimation extends EventDispatcher{
 		this.curveType = "centripetal" 
 		this.visible = true;
 
-		this.createUpdateHook();
+	 
 		this.createPath();
+        
+        
+        
+        
+        
+        
+        this.addEventListener('dispose', ()=>{ 
+             
+            this.dispose()
+        })
+        
 	}
 
 	static defaultFromView(viewer){
@@ -69,7 +99,7 @@ export class CameraAnimation extends EventDispatcher{
 			0.05 * camera.position.z + 0.95 * target.z,
 		);
 
-		const r = camera.position.distanceTo(target) * 0.3;
+		const r = 2//camera.position.distanceTo(target) * 0.3;
 
 		//const dir = target.clone().sub(camera.position).normalize();
 		const angle = Utils.computeAzimuth(camera.position, target);
@@ -93,180 +123,78 @@ export class CameraAnimation extends EventDispatcher{
 				targetCenter.z,
 			];
 
-			const cp = animation.createControlPoint();
-			cp.position.set(...cpPos);
-			cp.target.set(...targetPos);
+			animation.createControlPoint();
+			animation.posCurve.points[i].fromArray(cpPos)
+            animation.targetCurve.points[i].fromArray(targetPos)
+             
 		}
 
+        animation.changeCallback()
 		return animation;
 	}
 
-	createUpdateHook(){
-		const viewer = this.viewer;
-
-		viewer.addEventListener("update", () => {
-
-			const camera = viewer.scene.getActiveCamera();
-			const {width, height} = viewer.renderer.getSize(new THREE.Vector2());
-
-			this.node.visible = this.visible;
-
-			for(const cp of this.controlPoints){
-				
-				{ // position
-					const projected = cp.position.clone().project(camera);
-
-					const visible = this.visible && (projected.z < 1 && projected.z > -1);
-
-					if(visible){
-						const x = width * (projected.x * 0.5 + 0.5);
-						const y = height - height * (projected.y * 0.5 + 0.5);
-
-						cp.positionHandle.svg.style.left = x - cp.positionHandle.svg.clientWidth / 2;
-						cp.positionHandle.svg.style.top = y - cp.positionHandle.svg.clientHeight / 2;
-						cp.positionHandle.svg.style.display = "";
-					}else{
-						cp.positionHandle.svg.style.display = "none";
-					}
-				}
-
-				{ // target
-					const projected = cp.target.clone().project(camera);
-
-					const visible = this.visible && (projected.z < 1 && projected.z > -1);
-
-					if(visible){
-						const x = width * (projected.x * 0.5 + 0.5);
-						const y = height - height * (projected.y * 0.5 + 0.5);
-
-						cp.targetHandle.svg.style.left = x - cp.targetHandle.svg.clientWidth / 2;
-						cp.targetHandle.svg.style.top = y - cp.targetHandle.svg.clientHeight / 2;
-						cp.targetHandle.svg.style.display = "";
-					}else{
-						cp.targetHandle.svg.style.display = "none";
-					}
-				}
-
-			}
-
-			this.line.material.resolution.set(width, height);
-
-			this.updatePath();
-
-			{ // frustum
-				const frame = this.at(this.t);
-				const frustum = this.frustum;
-
-				frustum.position.copy(frame.position);
-				frustum.lookAt(...frame.target.toArray());
-				frustum.scale.set(20, 20, 20);
-
-				frustum.material.resolution.set(width, height);
-			}
-
-		});
-	}
-
-	createControlPoint(index){
+	 
 
+	createControlPoint(index){ 
+        const length = this.posCurve.points.length
+        const position = new THREE.Vector3
+        const target = new THREE.Vector3
+        
 		if(index === undefined){
-			index = this.controlPoints.length;
+			index = length;
 		}
-
-		const cp = new ControlPoint();
-
-
-		if(this.controlPoints.length >= 2 && index === 0){
-			const cp1 = this.controlPoints[0];
-			const cp2 = this.controlPoints[1];
-
-			const dir = cp1.position.clone().sub(cp2.position).multiplyScalar(0.5);
-			cp.position.copy(cp1.position).add(dir);
-
-			const tDir = cp1.target.clone().sub(cp2.target).multiplyScalar(0.5);
-			cp.target.copy(cp1.target).add(tDir);
-		}else if(this.controlPoints.length >= 2 && index === this.controlPoints.length){
-			const cp1 = this.controlPoints[this.controlPoints.length - 2];
-			const cp2 = this.controlPoints[this.controlPoints.length - 1];
-
-			const dir = cp2.position.clone().sub(cp1.position).multiplyScalar(0.5);
-			cp.position.copy(cp1.position).add(dir);
-
-			const tDir = cp2.target.clone().sub(cp1.target).multiplyScalar(0.5);
-			cp.target.copy(cp2.target).add(tDir);
-		}else if(this.controlPoints.length >= 2){
-			const cp1 = this.controlPoints[index - 1];
-			const cp2 = this.controlPoints[index];
-
-			cp.position.copy(cp1.position.clone().add(cp2.position).multiplyScalar(0.5));
-			cp.target.copy(cp1.target.clone().add(cp2.target).multiplyScalar(0.5));
+        
+
+		if(length >= 2 && index === 0){ 
+			const dir = new THREE.Vector3().subVectors(this.posCurve.points[0], this.posCurve.points[1] ) 
+			position.copy(this.posCurve.points[0]).add(dir);
+			
+            const tDir = new THREE.Vector3().subVectors(this.targetCurve.points[0], this.targetCurve.points[1] ) 
+			target.copy(this.targetCurve.points[0]).add(dir);
+			 
+		}else if(length >= 2 && index === length){ 
+            const dir = new THREE.Vector3().subVectors(this.posCurve.points[length-1], this.posCurve.points[length-2] ) 
+			position.copy(this.posCurve.points[length-2]).add(dir);
+			 
+            const tDir = new THREE.Vector3().subVectors(this.targetCurve.points[length-1], this.targetCurve.points[length-2] ) 
+			target.copy(this.targetCurve.points[length-2]).add(dir);
+			 
+		}else if(length >= 2){ 
+			position.copy(this.posCurve.points[index-1].clone().add(this.posCurve.points[index]).multiplyScalar(0.5));
+			target.copy(this.targetCurve.points[index-1].clone().add(this.targetCurve.points[index]).multiplyScalar(0.5));
 		}
 
-		// cp.position.copy(viewer.scene.view.position);
-		// cp.target.copy(viewer.scene.view.getPivot());
-
-		cp.positionHandle = this.createHandle(cp.position, 'red');
-		cp.targetHandle = this.createHandle(cp.target, 'blue');
-
-		this.controlPoints.splice(index, 0, cp);
+            
+        this.posCurve.addPoint(position, index)
+        this.targetCurve.addPoint(target, index)
+  
 
 		this.dispatchEvent({
-			type: "controlpoint_added",
-			controlpoint: cp,
+			type: "controlpoint_added", 
+            index
 		});
 
-		return cp;
+		 
 	}
 
-	removeControlPoint(cp){
-		this.controlPoints = this.controlPoints.filter(_cp => _cp !== cp);
-
-		this.dispatchEvent({
+	 
+    removeControlPoint(index){
+        this.posCurve.removePoint(index)
+        this.targetCurve.removePoint(index)
+        this.dispatchEvent({
 			type: "controlpoint_removed",
-			controlpoint: cp,
+			index
 		});
+        
+    }
 
-		cp.positionHandle.svg.remove();
-		cp.targetHandle.svg.remove();
 
-		// TODO destroy cp
-	}
 
 	createPath(){
-
-		{ // position
-			const geometry = new LineGeometry();
-
-			let material = new LineMaterial({ 
-				color: 0x00ff00, 
-				dashSize: 5, 
-				gapSize: 2,
-				lineWidth: 2, 
-				resolution:  new THREE.Vector2(1000, 1000),
-			});
-
-			const line = new Line2(geometry, material);
-
-			this.line = line;
-			this.node.add(line);
-		}
-
-		{ // target
-			const geometry = new LineGeometry();
-
-			let material = new LineMaterial({ 
-				color: 0x0000ff, 
-				dashSize: 5, 
-				gapSize: 2,
-				lineWidth: 2, 
-				resolution:  new THREE.Vector2(1000, 1000),
-			});
-
-			const line = new Line2(geometry, material);
-
-			this.targetLine = line;
-			this.node.add(line);
-		}
+        this.posCurve = new CurveCtrl([],getLineMat('position'), colors.position);
+        this.targetCurve = new CurveCtrl([], getLineMat('target'), colors.target); 
+        this.node.add(this.posCurve)
+        this.node.add(this.targetCurve)
 	}
 
 	createFrustum(){
@@ -274,105 +202,39 @@ export class CameraAnimation extends EventDispatcher{
 		const f = 0.3;
 
 		const positions = [
-			 0,  0,  0,
-			-f, -f, +1,
-
-			 0,  0,  0,
-			 f, -f, +1,
-
-			 0,  0,  0,
-			 f,  f, +1,
+			new THREE.Vector3( 0,  0,  0),
+			new THREE.Vector3(-f, -f, +1),
 
-			 0,  0,  0,
-			-f,  f, +1,
+			new THREE.Vector3( 0,  0,  0),
+			new THREE.Vector3( f, -f, +1),
 
-			-f, -f, +1,
-			 f, -f, +1,
+			new THREE.Vector3( 0,  0,  0),
+			new THREE.Vector3( f,  f, +1),
 
-			 f, -f, +1,
-			 f,  f, +1,
+			new THREE.Vector3( 0,  0,  0),
+			new THREE.Vector3(-f,  f, +1),
 
-			 f,  f, +1,
-			-f,  f, +1,
+			new THREE.Vector3(-f, -f, +1),
+			new THREE.Vector3( f, -f, +1),
 
-			-f,  f, +1,
-			-f, -f, +1,
-		];
+			new THREE.Vector3( f, -f, +1),
+			new THREE.Vector3( f,  f, +1),
 
-		const geometry = new LineGeometry();
+			new THREE.Vector3( f,  f, +1),
+			new THREE.Vector3(-f,  f, +1),
 
-		geometry.setPositions(positions);
-		geometry.verticesNeedUpdate = true;
-		geometry.computeBoundingSphere();
+			new THREE.Vector3(-f,  f, +1),
+			new THREE.Vector3(-f, -f, +1),
+		] 
 
-		let material = new LineMaterial({ 
-			color: 0xff0000, 
-			lineWidth: 2, 
-			resolution:  new THREE.Vector2(1000, 1000),
-		});
-
-		const line = new Line2(geometry, material);
-		line.computeLineDistances();
-		
+        
+		//geometry.computeBoundingSphere();//? 
+		const line = LineDraw.createFatLine( positions, {material:getLineMat('frustum')})
+        //line.scale.set(20, 20, 20); 
 		return line;
 	}
 
-	updatePath(){
-
-		{ // positions
-			const positions = this.controlPoints.map(cp => cp.position);
-			const first = positions[0];
-
-			const curve = new THREE.CatmullRomCurve3(positions);
-			curve.curveType = this.curveType;
-
-			const n = 100;
-
-			const curvePositions = [];
-			for(let k = 0; k <= n; k++){
-				const t = k / n;
-
-				const position = curve.getPoint(t).sub(first);
-
-				curvePositions.push(position.x, position.y, position.z);
-			}
-
-			this.line.geometry.setPositions(curvePositions);
-			this.line.geometry.verticesNeedUpdate = true;
-			this.line.geometry.computeBoundingSphere();
-			this.line.position.copy(first);
-			this.line.computeLineDistances();
-
-			this.cameraCurve = curve;
-		}
-
-		{ // targets
-			const positions = this.controlPoints.map(cp => cp.target);
-			const first = positions[0];
-
-			const curve = new THREE.CatmullRomCurve3(positions);
-			curve.curveType = this.curveType;
-
-			const n = 100;
-
-			const curvePositions = [];
-			for(let k = 0; k <= n; k++){
-				const t = k / n;
-
-				const position = curve.getPoint(t).sub(first);
-
-				curvePositions.push(position.x, position.y, position.z);
-			}
-
-			this.targetLine.geometry.setPositions(curvePositions);
-			this.targetLine.geometry.verticesNeedUpdate = true;
-			this.targetLine.geometry.computeBoundingSphere();
-			this.targetLine.position.copy(first);
-			this.targetLine.computeLineDistances();
-
-			this.targetCurve = curve;
-		}
-	}
+	 
 
 	at(t){
 		
@@ -382,7 +244,7 @@ export class CameraAnimation extends EventDispatcher{
 			t = 0;
 		}
 
-		const camPos = this.cameraCurve.getPointAt(t);
+		const camPos = this.posCurve.getPointAt(t);
 		const target = this.targetCurve.getPointAt(t);
 
 		const frame = {
@@ -397,87 +259,13 @@ export class CameraAnimation extends EventDispatcher{
 		this.t = t;
 	}
 
-	createHandle(vector, color){
-		
-		const svgns = "http://www.w3.org/2000/svg";
-		const svg = document.createElementNS(svgns, "svg");
-
-		svg.setAttribute("width", "2em");
-		svg.setAttribute("height", "2em");
-		svg.setAttribute("position", "absolute");
-
-		svg.style.left = "50px";
-		svg.style.top = "50px";
-		svg.style.position = "absolute";
-		svg.style.zIndex = "10000";
-
-		const circle = document.createElementNS(svgns, 'circle');
-		circle.setAttributeNS(null, 'cx', "1em");
-		circle.setAttributeNS(null, 'cy', "1em");
-		circle.setAttributeNS(null, 'r', "0.5em");
-		circle.setAttributeNS(null, 'style', 'fill: '+color+'; stroke: black; stroke-width: 0.2em;' );
-		svg.appendChild(circle);
-
-
-		const element = this.viewer.renderer.domElement.parentElement;
-		element.appendChild(svg);
-
-
-		const startDrag = (evt) => {
-			this.selectedElement = svg;
-
-			document.addEventListener("mousemove", drag);
-		};
-
-		const endDrag = (evt) => {
-			this.selectedElement = null;
-
-			document.removeEventListener("mousemove", drag);
-		};
-
-		const drag = (evt) => {
-			if (this.selectedElement) {
-				evt.preventDefault();
-
-				const rect = viewer.renderer.domElement.getBoundingClientRect();
-
-				const x = evt.clientX - rect.x;
-				const y = evt.clientY - rect.y;
-
-				const {width, height} = this.viewer.renderer.getSize(new THREE.Vector2());
-				const camera = this.viewer.scene.getActiveCamera();
-				//const cp = this.controlPoints.find(cp => cp.handle.svg === svg);
-				const projected = vector.clone().project(camera);
-
-				projected.x = ((x / width) - 0.5) / 0.5;
-				projected.y = (-(y - height) / height - 0.5) / 0.5;
-
-				const unprojected = projected.clone().unproject(camera);
-				vector.set(unprojected.x, unprojected.y, unprojected.z);
-
-
-			}
-		};
-
-		svg.addEventListener('mousedown', startDrag);
-		svg.addEventListener('mouseup', endDrag);
-
-		const handle = {
-			svg: svg,
-		};
-
-		return handle;
-	}
+	 
 
 	setVisible(visible){
 		this.node.visible = visible;
-
-		const display = visible ? "" : "none";
-
-		for(const cp of this.controlPoints){
-			cp.positionHandle.svg.style.display = display;
-			cp.targetHandle.svg.style.display = display;
-		}
+ 
+        this.posCurve.visible = visible
+        this.targetCurve.visible = visible
 
 		this.visible = visible;
 	}
@@ -512,18 +300,43 @@ export class CameraAnimation extends EventDispatcher{
 			viewer.scene.view.lookAt(frame.target);
 
 
+            this.updateFrustum()
+
+
 			if(t > 1){
 				this.setVisible(originalyVisible);
 
 				this.viewer.removeEventListener("update", onUpdate);
 			}
-
+            
+            
 		};
 
 		this.viewer.addEventListener("update", onUpdate);
 
 	}
 
+    updateFrustum(){ // 
+        const frame = this.at(this.t);
+        const frustum = this.frustum;
+
+        frustum.position.copy(frame.position);
+        frustum.lookAt(...frame.target.toArray());
+        
+    }
+
+    changeCallback(){
+        this.posCurve.update()
+        this.targetCurve.update()
+        this.updateFrustum()
+    }
+
+    dispose(){//add
+        this.posCurve.dispatchEvent({type:'dispose'}) 
+        this.targetCurve.dispatchEvent({type:'dispose'}) 
+        this.node.parent.remove(this.node);
+    }
 }
 
 
+//scene.removeCameraAnimation

+ 75 - 86
src/modules/Images360/Images360.js

@@ -42,7 +42,7 @@ const HighMapCubeWidth = 1
  
 export class Images360 extends EventDispatcher{
 
-	constructor(viewer, params){
+	constructor(viewer ){
 		super();
 
 		this.viewer = viewer;
@@ -59,7 +59,7 @@ export class Images360 extends EventDispatcher{
         
          
         this.cube = new THREE.Mesh(new THREE.BoxBufferGeometry(1,1,1,1),cm);
-        this.updateCube(params) 
+ 
         this.cube.visible = false; 
          
         this.cube.layers.set(Potree.config.renderLayers.skybox)
@@ -624,16 +624,16 @@ export class Images360 extends EventDispatcher{
             })
         }            
          
-        
-        this.setProjectedPanos({
-            progress:0,
-            ifSkybox: this.cube.visible,
-            ifPointcloud : config.transition.pointUsePanoTex,
-            easeInOutRatio : pointcloudVisi ? 0.3 : 0,
-            pano0:this.currentPano,
-            pano1:pano
-        })
-           
+        //if(config.transition.showSkybox || config.transition.pointUsePanoTex){
+            this.setProjectedPanos({
+                progress:0,
+                ifSkybox: this.cube.visible,
+                ifPointcloud : config.transition.pointUsePanoTex,
+                easeInOutRatio : pointcloudVisi ? 0.3 : 0,
+                pano0:this.currentPano,
+                pano1:pano
+            })
+        //}
          
         
         
@@ -758,15 +758,15 @@ export class Images360 extends EventDispatcher{
                 e.material.setProjectedPanos(pano, pano, 0)
             })
         }  */
-             
-        this.setProjectedPanos({
-            progress:0,
-            ifSkybox: this.cube.visible,
-            ifPointcloud : config.atPano.pointUsePanoTex, 
-            pano0:pano,
-            pano1:pano
-        })
- 
+        //if(config.transition.showSkybox || config.transition.pointUsePanoTex){  
+            this.setProjectedPanos({
+                progress:0,
+                ifSkybox: this.cube.visible,
+                ifPointcloud : config.atPano.pointUsePanoTex, 
+                pano0:pano,
+                pano1:pano
+            })
+        //}
         
         let newCamPos = pano.position.clone()
         let target = newCamPos.clone().add(viewer.scene.view.direction)  
@@ -1540,7 +1540,59 @@ export class Images360 extends EventDispatcher{
     //缩小后继续显示cube呢还是不显示?  不显示的话,就要把cube上的复制到renderTarget上……会不会又崩溃,or没加载的显示???
     
     
+    addPanoData(data, datasetId){
+        //data[0].file_id = '00019'
+         
+        if(data.data) data = data.data 
+        if(data.length == 0)console.error(datasetId + ' 没有漫游点') 
+        //data = data.sort(function(a,b){return a.id-b.id})
+        
+        data.forEach((info)=>{  
+            if(Potree.fileServer){
+                info.id = this.panos.length             //把info的id的一长串数字改简单点
+            } 
+            let pano = new Panorama( info,  viewer.transform, this   );
+            
+            /* pano.mesh.layers.set(Potree.config.renderLayers.marker)
+            pano.marker.layers.set(Potree.config.renderLayers.marker)  */
+         
+            this.panos.push(pano);
+
+        })  
+          
+    }
+    
+    
+    loadDone(){
+        viewer.setObjectLayers(this.node, 'marker'/* 'sceneObjects' */)
+        this.updateCube(viewer.bound)
+        
+        this.panos.forEach(e=>{
+            e.label && viewer.setObjectLayers(e.label, 'bothMapAndScene') 
+        })
+        
+        this.tileDownloader.setPanoData(this.panos, [] /* , Potree.settings.number */);
+
+        {
+            var panosBound = new THREE.Box3
+            this.panos.forEach(pano=>{
+                panosBound.expandByPoint(pano.position)
+            }) 
+            let center = panosBound.getCenter(new THREE.Vector3)
+            let minBound = (new THREE.Box3()).setFromCenterAndSize(center, new THREE.Vector3(1,1,1))
+            panosBound.union(minBound)
+           
+            this.bound = {
+                bounding:panosBound,
+                size: panosBound.getSize(new THREE.Vector3),
+                center,
+            }
+        }
+        
+        
+    }
     
+            
 };
 
 
@@ -1668,71 +1720,8 @@ Images360.sortFunctions =  {//排序函数,涉及到两个item相减
         return function(t, i) {
             return t.floorPosition.distanceTo(e) - i.floorPosition.distanceTo(e)
         }
-    }, 
-    
-    
+    },  
 }    
-
-export class Images360Loader{ 
-
-    static async load(viewer, params, callback ){
-  
-		let center = params.center.clone()
-        center = {lat:center.y, lon:center.x} //中心点 
-        
-        Potree.loadPanos(center,(data)=>{
-            //data[0].file_id = '00019'
-             
-            if(data.data) data = data.data
-            if(data.length == 0)console.error('没有漫游点')
-            
-            let images360 = new Images360(viewer, params);
-            
-            data = data.sort(function(a,b){return a.id-b.id})
-            
-            data.forEach((info,i)=>{  
-                if(Potree.fileServer){
-                    info.id = i //info的id是一长串数字,改简单点
-                } 
-                let pano = new Panorama( info,  params.transform, images360   );
-                
-                /* pano.mesh.layers.set(Potree.config.renderLayers.marker)
-                pano.marker.layers.set(Potree.config.renderLayers.marker)  */
-             
-                images360.panos.push(pano);
-
-            })
-            viewer.setObjectLayers(images360.node, 'marker'/* 'sceneObjects' */)
-            
-            
-            images360.panos.forEach(e=>{
-                e.label && viewer.setObjectLayers(e.label, 'bothMapAndScene') 
-            })
-
-
-            
-            viewer.images360 = window.images360 = images360//add
-            images360.tileDownloader.setPanoData(images360.panos, [] /* , Potree.settings.number */);
-
-            {
-                var panosBound = new THREE.Box3
-                images360.panos.forEach(pano=>{
-                    panosBound.expandByPoint(pano.position)
-                }) 
-                let center = panosBound.getCenter(new THREE.Vector3)
-                let minBound = (new THREE.Box3()).setFromCenterAndSize(center, new THREE.Vector3(1,1,1))
-                panosBound.union(minBound)
-               
-                images360.bound = {
-                    bounding:panosBound,
-                    size: panosBound.getSize(new THREE.Vector3),
-                    center,
-                }
-            }
-
-            callback && callback(images360)
-        })   
-	}
-};
+ 
 
 

+ 8 - 9
src/modules/Images360/Panorama.js

@@ -70,16 +70,15 @@ class Panorama extends EventDispatcher{
         
         this.pointcloud = viewer.scene.pointclouds.find(e=>e.dataset_id == o.dataset_id) || viewer.scene.pointclouds[0]
         this.pointcloud.panos.push(this)
-        this.pointcloud.addEventListener('isVisible',(e)=>{ 
-            /* if(!e.visible){//数据集隐藏时漫游点也隐藏
-                e.reason == 'datasetSelection' && viewer.updateVisible(this, 'pointcloudVisi', false) 
-            }else{
-                console.log('pointcloudVisi 1')
-                viewer.updateVisible(this, 'pointcloudVisi', true) 
-            } */
-            e.reason == 'datasetSelection' && viewer.updateVisible(this, 'pointcloudVisi', e.visible) 
+        /* this.pointcloud.addEventListener('isVisible',(e)=>{ 
+             
+            var visible = viewer.getObjVisiByReason(this.pointcloud, 'datasetSelection')
+            console.log('datasetVisi', visible)
+            viewer.updateVisible(this, 'pointcloudVisi', visible) 
             
-        })
+            //e.reason == 'datasetSelection' && viewer.updateVisible(this, 'pointcloudVisi', e.visible) 
+            
+        }) */
         this.addEventListener('isVisible',(e)=>{//是否显示该点的mesh(不显示也能走)
             this.marker.visible = e.visible
             Potree.settings.showPanoMesh && (this.mesh.visible = e.visible)

+ 2 - 1
src/modules/clipModel/Clip.js

@@ -108,7 +108,7 @@ var Clip = {
         viewer.inputHandler.toggleSelection(this.box);
         viewer.inputHandler.fixSelection = true
         viewer.transformationTool.frame.material.color.set(Potree.config.clip.color)//navvis 15899953 
-         
+        viewer.setPointStandardMat(true) 
     },
     
     leave:function(){
@@ -124,6 +124,7 @@ var Clip = {
         
         viewer.setView(this.previousView)
         viewer.setLimitFar(true)
+        viewer.setPointStandardMat(false) 
     },
     
     getTarget:function(boundCenter){//box位置。要找一个有点云的地方。方案1相机位置, 方案2接近相机的漫游点, 方案3接近中心的漫游点。选择方案2,因最大概率有点云

+ 1 - 2
src/modules/datasetAlignment/Alignment.js

@@ -164,8 +164,7 @@ var Alignment = {
                 //transformMatrix: e.transformMatrix.elements,
             }
         })
-        data = data[0]//暂时只传第一个
-        
+        //data = JSON.stringify(data)
         
         //test: 退出后保留结果
         if(!Potree.settings.isOfficial){

+ 15 - 1
src/modules/siteModel/SiteModel.js

@@ -779,6 +779,14 @@ var SiteModel = {
     
     findPanos: function(){
         
+        {//清空:
+            this.entities.forEach(entity=>{
+                entity.panos = []
+                entity.flagPano = null
+            }) 
+        } 
+        
+        
         viewer.images360.panos.forEach(pano=>{
             let result = this.pointInWhichEntity(pano.position, 'room');
             
@@ -886,7 +894,13 @@ var SiteModel = {
         viewer.images360.flyToPano(aimPano)
     },
 
-    
+    focusEntity(id){
+        var entity = this.entities.find(e => e.sid == id)
+        let boundingBox = entity.getBound()
+        let boundSize = boundingBox.getSize(new THREE.Vector3())
+        let center = boundingBox.getCenter(new THREE.Vector3())
+        this.SplitScreen.focusOnObject(boundSize, center) 
+    },
 }
 
 /* 

+ 3 - 3
src/navigation/InputHandler.js

@@ -702,7 +702,7 @@ export class InputHandler extends EventDispatcher {
             {pickClipped: true, isMeasuring: this.isMeasuring, pickWindowSize}
         );
             
-        
+        //console.log(viewport.name , intersectPoint &&  intersectPoint.location )
         
         if(viewport.camera.type == 'OrthographicCamera'/*  == 'mapViewport' */){ 
             let pos3d = new THREE.Vector3(this.pointer.x,this.pointer.y,-1).unproject(viewport.camera); //z:-1朝外   
@@ -891,7 +891,7 @@ export class InputHandler extends EventDispatcher {
              
             
              
-            
+ 
             
             
             
@@ -1133,7 +1133,7 @@ export class InputHandler extends EventDispatcher {
         )
         
         
-        viewer.emit('raycaster', {viewport: this.hoverViewport})//add
+        viewer.dispatchEvent( {type:'raycaster',  viewport: this.hoverViewport})//add
 		let intersections = raycaster.intersectObjects(interactables.filter(o => o.visible), true); //原本是false 检测不到children
          
         intersections = intersections.map(e=>{//add 转化为interactables

+ 22 - 7
src/objects/Label.js

@@ -1,8 +1,13 @@
 import * as THREE from "../../libs/three.js/build/three.module.js";
-import {Utils} from "../utils.js";
+import {Utils} from "../utils.js"; 
+import { EventDispatcher } from "../EventDispatcher.js";
 
-class Label{
+
+
+class Label  extends EventDispatcher{
     constructor(o={}){
+        super()
+        
         this.position = o.pos;
         this.text = o.text || '';
         this.elem = $('<div class="hide"><a></a></div>');
@@ -13,11 +18,18 @@ class Label{
         this.dom = o.dom || viewer.renderArea
         this.camera = o.camera || viewer.scene.getActiveCamera() 
         
-        viewer.addEventListener('camera_changed', ()=>{
-            this.update()
-        })
-       
         
+        let update = (e)=>{
+            this.update(e) 
+        }
+        viewer.addEventListener('camera_changed',  update)
+           
+         
+        this.addEventListener('dispose', ()=>{
+            viewer.removeEventListener('camera_changed',  update)
+            this.dispose()
+            
+        })
         
     }
      
@@ -60,9 +72,12 @@ class Label{
         this.position = pos;
     }
     
-    remove(){
+    dispose(){
         this.elem.remove();
+        this.removeAllListeners()
     }
+     
+     
 }
 
 export default Label;

+ 37 - 12
src/objects/Magnifier.js

@@ -24,7 +24,7 @@ export default class Magnifier extends THREE.Object3D {//放大镜or望远镜
 	constructor (viewer) {
 		super()
         this.width = this.height = width2dPX/*  * window.devicePixelRatio */;
-        this.camera = new THREE.PerspectiveCamera(50, 1, 0.1, 10000);  //fov aspect near far
+        this.camera = new THREE.PerspectiveCamera(50, 1, 0.01, 10000);  //fov aspect near far
         this.camera.up = new THREE.Vector3(0,0,1) 
         
         
@@ -34,24 +34,42 @@ export default class Magnifier extends THREE.Object3D {//放大镜or望远镜
         })
         this.viewport.setResolution(this.width, this.height,0,0)
         
-        {//使放大镜里的pointDensity是'magnifier', 最高质量。
+        { 
             let density
             let sizeType
+            let colorType
+            let opacityBefore = new Map()
             this.viewport.beforeRender = ()=>{
+                viewer.scene.pointclouds.forEach(e=>{//因为更改pointDensity时会自动变opacity,所以这项最先获取
+                    opacityBefore.set(e,e.temp.pointOpacity)  
+                }) 
+                
+                
+                //使放大镜里的pointDensity是'magnifier'  最高质量。
                 density = Potree.settings.pointDensity 
                 Potree.settings.pointDensity = 'magnifier' 
                  
                 viewer.scene.pointclouds.forEach(e=>{//因为全景模式的pointSizeType是fixed所以要还原下
                     sizeType = e.material.pointSizeType  
                     e.material.pointSizeType = Potree.config.material.pointSizeType  
-                })
+                     
+                    //材质
+                    colorType = e.material.activeAttributeName
+                    e.material.activeAttributeName = 'rgba'
+                    e.changePointOpacity(1) 
+                   
+                }) 
             };
+            
+            
             this.viewport.afterRender = ()=>{
                 Potree.settings.pointDensity = density
                 
                 viewer.scene.pointclouds.forEach(e=>{
                     e.material.pointSizeType = sizeType
-                })
+                    e.material.activeAttributeName = colorType  
+                    e.changePointOpacity(opacityBefore.get(e))  
+                }) 
             } 
         }
         
@@ -91,13 +109,20 @@ export default class Magnifier extends THREE.Object3D {//放大镜or望远镜
             depthTest: !1,
             //depthWrite: !1,
         }))
+        this.targetPoint = new THREE.Object3D;
         
-        this.targetPoint = new THREE.Mesh(sphereGeo, new THREE.MeshBasicMaterial({ 
+        this.targetPoint.add(new THREE.Mesh(sphereGeo, new THREE.MeshBasicMaterial({ 
             color:"#ff0000",
             transparent:true,
-            opacity:0.65,
-             
-        }))
+            opacity:0.5,  
+        })))
+        this.targetPoint.add(new THREE.Mesh(sphereGeo, new THREE.MeshBasicMaterial({ 
+            color:"#ff0000",
+            transparent:true,
+            opacity:0.2, 
+            depthTest:false  //被遮挡层
+        })))
+        
         this.targetPoint.name = 'magnifierPointTarget'
         viewer.scene.scene.add(this.targetPoint)
         viewer.setObjectLayers(this.targetPoint, 'magnifierContent' )
@@ -119,7 +144,7 @@ export default class Magnifier extends THREE.Object3D {//放大镜or望远镜
             if(e.viewport == viewer.mainViewport) this.update() //不过intersectPoint没更新 
         }) 
             
-
+         
         
         
         this.mesh.layers.set(Potree.config.renderLayers.magnifier);
@@ -184,9 +209,9 @@ export default class Magnifier extends THREE.Object3D {//放大镜or望远镜
     
    
     
-    
-    update(aimPos){//相机靠近 navvis的做法
-        var dontRender = this.dontRender || !(aimPos instanceof THREE.Vector3)
+    //注意:在鼠标没有移动的时候,无法获取到最新的intersect, 放大镜内的内容可能是错误的。全景模式下更奇怪,原因未知
+    update(aimPos){//相机靠近 navvis的做法 
+        var dontRender = this.dontRender || !(aimPos instanceof THREE.Vector3) || Potree.settings.displayMode == 'showPanos' && viewer.images360.flying
         aimPos = aimPos instanceof THREE.Vector3 ?  aimPos : this.aimPos
         if(!aimPos  || !this.visible)return
         

+ 22 - 20
src/objects/Reticule.js

@@ -13,7 +13,7 @@ let defaultOpacity =  0.7
 export default class Reticule extends THREE.Mesh{
     constructor(viewer){
         var defaultTex = texLoader.load(Potree.resourcePath+'/textures/whiteCircle.png'/* reticule-256x256.png'  */)  
-        super(new THREE.PlaneBufferGeometry(0.13,0.13,1,1),new THREE.MeshBasicMaterial({
+        super(new THREE.PlaneBufferGeometry(0.11,0.11,1,1),new THREE.MeshBasicMaterial({
             side: THREE.DoubleSide , 
             map: defaultTex,
             transparent:true,
@@ -93,12 +93,10 @@ export default class Reticule extends THREE.Mesh{
 
 
     move(e){ 
-    
-        if(e.type == "global_mousemove" && (e.isTouch || e.buttons != Buttons.NONE) && this.state != 'crosshair')
+        if(e.type == "global_mousemove" && (e.isTouch || e.buttons != Buttons.NONE) && this.state != 'crosshair'){
             return//按下时不更新,除非拖拽测量
-    
-       
-        
+        }
+           
         this.mouseLastMoveTime = Date.now()
         
         this.updatePosition(e.intersectPoint, e.hoverViewport)
@@ -195,34 +193,38 @@ export default class Reticule extends THREE.Mesh{
     
 
     updatePosition(intersectPoint, viewport ){ //在地图(当地图融合到viewer时)和场景里都显示且完全相同(大小可能不同)
+         
         if (viewer.getObjVisiByReason(this, 'force')) {//没有被强制隐藏,如进入某个页面后强制不显示
-            if (!intersectPoint /* || !intersectPoint.point.normal */)
-                return //this.hide();
+            if (!intersectPoint /* || !intersectPoint.point.normal */){ 
+                 return //this.hide();   
+            }
+                
             var atMap = !intersectPoint.location
             let location = intersectPoint.location || intersectPoint.orthoIntersect.clone()
             let normal  
             
-            if(atMap){ 
-                normal =  new THREE.Vector3(0,0,1)//地图无normal
-                location.setZ(0);//低于相机高度即可
-               
-            }else{
-                normal = new THREE.Vector3().fromArray(intersectPoint.point.normal ).applyMatrix4(intersectPoint.pointcloud.transformMatrix);
-                
-            }
-             
             
             //地图上要瞬间变化 , 因为要使needRender为true很麻烦
             this.show(atMap ? 0 : 300);
             
-            if(atMap){
+            
+            if(atMap){ 
+                normal =  new THREE.Vector3(0,0,1)//地图无normal
+                location.setZ(0);//低于相机高度即可
                 this.direction = normal.clone()
             }else{
+                //console.log(location) 
+                normal = new THREE.Vector3().fromArray(intersectPoint.point.normal ).applyMatrix4(intersectPoint.pointcloud.rotateMatrix);
+                
                 this.direction = this.direction.multiplyScalar(.8); 
-                this.direction.add(normal.clone().multiplyScalar(.2));
+                this.direction.add(normal.clone().multiplyScalar(.2)); 
+                //this.direction = normal.clone() //改为瞬间变化,否则刚hover上某个点时看起来不太对
             }
+             
+             
+            
             
-            this.position.copy(location).add(normal.clone().multiplyScalar(.01));
+            this.position.copy(location)/* .add(normal.clone().multiplyScalar(.01)); */
             this.updateMatrix();  //lookAt之前要保证得到matrix
             this.lookAt(this.position.clone().add(this.direction));
             

+ 26 - 16
src/objects/Sprite.js

@@ -19,27 +19,33 @@ export default class Sprite extends THREE.Mesh{
         this.useViewport = null
         this.viewports = options.viewports//指定更新的viewports
         
-        viewer.addEventListener("camera_changed", (e)=>{
-            /* if(viewer.viewports.length == 1){//直接更新。如果有多个不在这更新,在"render.begin"
-                this.update(e)
-            } */
-            this.update(e)            
-        });
         
         
-        viewer.mapViewer.addEventListener("camera_changed", (e)=>{
-            this.update(e)     
-        });
+        let update = (e)=>{
+            this.update(e) 
+        }
+        viewer.mapViewer.addEventListener("camera_changed",  update) 
+        viewer.addEventListener("camera_changed",  update) 
+        /* if(viewer.viewports.length == 1){//直接更新。如果有多个不在这更新,在"render.begin"
+            this.update(e)
+        } */
+         
         
-        viewer.addEventListener("render.begin", (e)=>{//before render
-            //if(viewer.viewports.length > 1) this.update(e)  //magnifier时要禁止吗
+        let applyMatrix = (e)=>{
+            this.applyMatrix(e)
+        }
+        viewer.addEventListener("raycaster", applyMatrix)        //before render
+        viewer.addEventListener("render.begin", applyMatrix) //before render  //magnifier时要禁止吗
             
-            this.applyMatrix(e) 
-        });
-        
-        viewer.on("raycaster", (e)=>{//before render
-            this.applyMatrix(e) 
+        this.addEventListener('dispose', ()=>{
+            viewer.mapViewer.removeEventListener("camera_changed",  update) 
+            viewer.removeEventListener("camera_changed",  update) 
+            viewer.removeEventListener("raycaster", applyMatrix)        //before render
+            viewer.removeEventListener("render.begin", applyMatrix)
+             
+            this.dispose()
         })
+         
     }
     
     
@@ -120,4 +126,8 @@ export default class Sprite extends THREE.Mesh{
     }
     
      
+    dispose(){
+        this.removeAllListeners()
+        
+    }
 }

+ 5 - 0
src/objects/TextSprite.js

@@ -42,6 +42,9 @@ export class TextSprite extends THREE.Object3D{
         this.name = options.name
         
 		//this.setText(text);
+        
+        
+        this.addEventListener('dispose', this.dispose.bind(this)) 
 	}
 
 	setText(text){
@@ -165,6 +168,8 @@ export class TextSprite extends THREE.Object3D{
     dispose(){
         this.sprite.material.uniforms.map.value.dispose()
         this.parent && this.parent.remove(this)
+        this.sprite.dispatchEvent({type:'dispose'})
+        this.removeAllListeners()
     }
 
 }

+ 23 - 16
src/objects/fireParticle/explode/ExplodeParticle.js

@@ -16,38 +16,38 @@ const getTexture = ()=>{
 }
 
 const defaults = {
-    position: new THREE.Vector3(0, 0 , 4),
+    position: new THREE.Vector3(0, 0 , 1),
      
     positionShape: Shape.SPHERE,
     
     positionRange : new THREE.Vector3(1,1,1),       //cube
     
-    positionRadius: 3,     //sphere
+    positionRadius: 1.3,     //sphere
     
     velocityShape: Shape.SPHERE,
     
-    velocity: new THREE.Vector3(0.3,0.3, 2),   //cube
-    velocityRange: new THREE.Vector3(1, 1, 2), 
-    speed : 1,            //sphere
-    speedRange : 10,
+    velocity: new THREE.Vector3(0,0, 2),   //cube
+    velocityRange: new THREE.Vector3(0, 0, 1), 
+    speed : 0.1,            //sphere
+    speedRange : 0.3,
     
     size: 0.4,
     sizeRange: 2,
     //sizeTween: new Tween( [0, 0.05, 0.3, 0.45], [0, 1, 3, 0.1] ),
-    sizeTween: new Tween(  ),
+    sizeTween: new Tween([0,0.03,0.06,0.9 ],[0.3, 0.3, 3, 4 ]  ),
     
     
     color : new THREE.Vector3(1.0, 1.0, 1.0),
-    colorRange : new THREE.Vector3(0.0, 0.0, 0.0),
+    colorRange : new THREE.Vector3(0, 0, 0),
     colorTween : new Tween(),
     
     opacity : 1.0,
     opacityRange : 0.0 ,
-    opacityTween: new Tween( [0, 0.05, 0.3, 0.45], [1, 1, 0.5, 0] ), 
+    opacityTween: new Tween( [0, 0.06, 0.3, 0.8, 1], [0, 1, 0.5, 0.1, 0] ), 
     blendMode: THREE.AdditiveBlending,
     	 
-    acceleration : 0.1,         
-    accelerationRange : 0.5,
+    acceleration : 0,         
+    accelerationRange :0,
  
     angle : 0,
     angleRange : 0,
@@ -56,8 +56,8 @@ const defaults = {
     angleAcceleration : 0,
     angleAccelerationRange : 0,
  
-    particlesPerSecond: 10,
-    particleDeathAge: 1,
+    particlesPerSecond: 4,
+    particleDeathAge: 1.5,
 
 
 	
@@ -100,7 +100,7 @@ class ExplodeParticle extends THREE.Points{
         if(state){//重新一个个放出粒子,否则会一股脑儿全部出来,因为同时大于粒子周期了一起重新生成出现。
             setTimeout(()=>{//会先update一次delta为pageUnvisile的时间才触发
                 //归零
-                console.log('归零')
+                //console.log('归零')
                 this.age = 0;
                 
                 this.geometry.dispose()
@@ -211,11 +211,18 @@ class ExplodeParticle extends THREE.Points{
     }
 
     if(this.positionShape == Shape.SPHERE) {
-      const z = 2 * Math.random() - 1
+      /* const z = 2 * Math.random() - 1
       const t = Math.PI * 2 * Math.random()
       const r = Math.sqrt(1 - z*z)
       const vec3 = new THREE.Vector3(r * Math.cos(t), r * Math.sin(t), z)
-      particle.position = vec3.multiplyScalar(this.positionRadius) 
+      particle.position = vec3.multiplyScalar(this.positionRadius)  */
+      
+        const y = 2 * Math.random() - 1    
+        const t = Math.PI * 2 * Math.random();
+        const r = Math.sqrt( 1 - y*y ) ;
+        const vec3 = new THREE.Vector3( r * Math.cos(t), y, r * Math.sin(t)  );
+        particle.position = vec3.multiplyScalar(this.positionRadius)
+          
     }
 
     if(this.velocityShape == Shape.CUBE) {

+ 123 - 79
src/objects/fireParticle/fire/FireParticle.js

@@ -15,90 +15,37 @@ const getTexture = ()=>{
 }
 
 
- 
- 
-
-let createGeometry = function( radius, height, particleCount){
-    let geometry = new THREE.BufferGeometry()
-
-    var halfHeight = height * 0.5;
-    var position = new Float32Array(particleCount * 3);
-    var randam = new Float32Array(particleCount);
-    var sprite = new Float32Array(particleCount);
-
-    for (var i = 0; i < particleCount; i++) {
-
-        var r = Math.sqrt(Math.random()) * radius;
-        var angle = Math.random() * 2 * Math.PI;
-        position[i * 3 + 0] = Math.cos(angle) * r;
-        position[i * 3 + 2] = (radius - r) / radius * halfHeight + halfHeight;
-        position[i * 3 + 1] = Math.sin(angle) * r;
-        sprite[i] = 0.25 * (Math.random() * 4 | 0);
-        randam[i] = Math.random();
-
-        if (i === 0) {
-
-            // to avoid going out of Frustum
-            position[i * 3 + 0] = 0;
-            position[i * 3 + 1] = 0;
-            position[i * 3 + 2] = 0;
-        }
-    }
-
-    geometry.setAttribute('position', new THREE.BufferAttribute(position, 3));
-    geometry.setAttribute('randam', new THREE.BufferAttribute(randam, 1));
-    geometry.setAttribute('sprite', new THREE.BufferAttribute(sprite, 1));
-    return geometry;
-}
-
-
-
-let createMaterial = function(fov, color){
-    
-    const material = new THREE.ShaderMaterial( {
-        uniforms:{
-            color: { type: "c", value: new THREE.Color(color) },
-            size: { type: "f", value: 0.4},
-            u_sampler: { type: "t", value: getTexture() },
-            time: { type: "f", value: 0.0 },
-            heightOfNearPlane: { type: "f", value:0}  //相对far ,以确保画面缩放时点的大小也会缩放
-        },
-        vertexShader,
-        fragmentShader,
-        blending: THREE.AdditiveBlending,
-        depthTest: true,
-        depthWrite: false,
-        transparent: true
-
-    } );
-    
-    
-    return material
-}
-
-
-
 
 
 
 class FireParticle extends THREE.Points{
   
     constructor (prop) {
-        let fireRadius = prop.fireRadius || 1;
-        let fireHeight = prop.fireHeight || 3;
-        let particleCount = prop.particleCount || 200;
- 
+        super()
+        
+        for ( var key in prop ){
+            this[key] = prop[key]
+        }
+        
+        
+         
+        this.density = this.density || 1
+        
+        
+         
+        this.fireRadius = prop.fireRadius || 1;
+        this.fireHeight = prop.fireHeight || 5;  
+        
+        this.computeParams()
+        this.geometry = this.createGeometry( this.fireRadius, this.fireHeight, this.particleCount );
+         
         
-        let geometry = createGeometry( fireRadius, fireHeight, particleCount );
-        let material = createMaterial(  prop.fov, 0xff2200 );  //小蓝火:0x00338f
-        super(geometry, material)
         
+        this.material = this.createMaterial(  prop.fov, 0xff3200 );  //小蓝火:0x00338f
         
-        this.fireRadius = fireRadius
-        this.fireHeight = fireHeight
-        this.particleCount = particleCount
+      
          
-        prop.position && this.position.copy(prop.position)
+        //---?:
         this.velocity = new THREE.Vector3()
         this.acceleration = new THREE.Vector3()
         
@@ -126,13 +73,111 @@ class FireParticle extends THREE.Points{
         })  
         viewer.addEventListener('fov_changed',(e)=>{ 
             this.setFov(e.fov) 
-        })
+        })  
+    }
+
+ 
+    computeParams(){  
+        let length = (this.curve ? this.curve.wholeLength : 0) + this.fireRadius * 2 //加上首尾的半径
+        this.particleCount =  Math.ceil( this.fireRadius * this.fireHeight * length * this.density *  5  )        
+        console.log('fire particleCount',this.particleCount)
+    }
+
+    createGeometry( radius, height, particleCount){
+        let geometry = new THREE.BufferGeometry()
+        
+        
+        
+        var halfHeight = height * 0.5;
         
+        let count , points
+        if(this.positions.length>1){
+             
+            const spaceDis = 0.2;//间隔距离
+            
+            count = Math.ceil(this.curve.wholeLength / spaceDis) + 1 
+            console.log('count', count)
+            points = this.curve.getSpacedPoints( count );  //得到的数量会比count多一个
+            count = points.length  
+            //得到的点不太均匀,两端容易点少。
+            
+            
+        }
+         
         
+        var position = new Float32Array(particleCount * 3);
+        var randam = new Float32Array(particleCount);
+        var sprite = new Float32Array(particleCount);
+        var centerHeight = new Float32Array(particleCount);
+        
+        for (var i = 0; i < particleCount; i++) {
+            
+            var center = new THREE.Vector3().copy(this.positions.length>1 ? points[Math.floor(i/particleCount * count)] : this.positions[0])
+            centerHeight[i] = center.z
+            
+            if (i === 0) { 
+                // to avoid going out of Frustum
+                position[i * 3 + 0] = center.x;
+                position[i * 3 + 1] = center.y;
+                position[i * 3 + 2] = center.z;
+            }else{  
+                var r = Math.sqrt(Math.random()) * radius;
+                var angle = Math.random() * 2 * Math.PI;
+                position[i * 3 + 0] = center.x + Math.cos(angle) * r; 
+                position[i * 3 + 1] = center.y + Math.sin(angle) * r;
+                position[i * 3 + 2] = center.z + (radius - r) / radius * halfHeight + halfHeight; //不太明白这句为什么能达到height高度
+               
+                sprite[i] = 0.25 * (Math.random() * 4 | 0);
+                randam[i] = Math.random();
+                //center在底部
+            }
+            
+            
+        }
         
+        geometry.setAttribute('centerHeight', new THREE.BufferAttribute(centerHeight, 1));
+        geometry.setAttribute('position', new THREE.BufferAttribute(position, 3));
+        geometry.setAttribute('randam', new THREE.BufferAttribute(randam, 1));
+        geometry.setAttribute('sprite', new THREE.BufferAttribute(sprite, 1));
+        return geometry;
     }
-
     
+    
+    
+    
+    updateGeometry(){ 
+        this.computeParams()
+        this.geometry.dispose() 
+        this.geometry = this.createGeometry( this.fireRadius, this.fireHeight, this.particleCount )
+        
+    }
+
+
+    createMaterial(fov, color){
+        
+        const material = new THREE.ShaderMaterial( {
+            uniforms:{
+                color: { type: "c", value: new THREE.Color(color) },
+                size: { type: "f", value: THREE.Math.clamp(this.fireRadius * 1.2, 0.5, 5)},
+                u_sampler: { type: "t", value: getTexture() },
+                time: { type: "f", value: 0.0 },
+                heightOfNearPlane: { type: "f", value:0},  //相对far ,以确保画面缩放时点的大小也会缩放
+                fireHeight :{ type: "f", value:this.fireHeight}  ,
+            },
+            vertexShader,
+            fragmentShader,
+            blending: THREE.AdditiveBlending, //加法融合模式 glBlendFunc(GL_ONE, GL_ONE)
+            depthTest: true,
+            depthWrite: false,
+            transparent: true
+
+        } );
+        
+        
+        return material
+    }
+
+
     setSize(e){
         let viewport = e.viewport
         this.screenHeight = viewport.resolution.y
@@ -154,9 +199,8 @@ class FireParticle extends THREE.Points{
     
     
     update(delta){
-        /* let delta = clock.getDelta();
-        let elapsed = clock.getElapsedTime(); */
-        delta *= 0.75//更改速度
+        
+        delta *= 1//更改速度
         
         this.material.uniforms.time.value = (this.material.uniforms.time.value + delta) % 1;
         

+ 24 - 3
src/objects/fireParticle/fire/shader.js

@@ -1,11 +1,17 @@
 export const vertexShader = `
     attribute float randam;
     attribute float sprite;
-
+    attribute float centerHeight;  //add
+    
+    //uniform float fireHeight;  //add 
     uniform float time;
     uniform float size;
     uniform float heightOfNearPlane;
-
+    
+    
+    
+    
+    //varying float heightRatio;
     varying float vSprite;
     varying float vOpacity; 
     float PI = 3.14;
@@ -22,11 +28,17 @@ export const vertexShader = `
         float progressNeg = 1.0 - progress;
         float ease = quadraticIn( progress );
         float influence = sin( PI * ease );
-        vec3 newPosition = position * vec3( 1.0,  1.0 , ease);
+        //vec3 newPosition = position * vec3( 1.0,  1.0 , ease);
+        vec3 newPosition = position;
+        newPosition.z = (newPosition.z - centerHeight) * ease + centerHeight;
+         
         gl_Position = projectionMatrix * modelViewMatrix * vec4( newPosition, 1.0 );
         gl_PointSize = ( heightOfNearPlane * size ) / gl_Position.w;
         vOpacity = min( influence * 4.0, 1.0 ) * progressNeg;
         vSprite = sprite;
+        
+        //heightRatio = (newPosition.z - centerHeight) / fireHeight ;
+        
     }
 ` 
 
@@ -36,10 +48,19 @@ export const fragmentShader = `
 
     varying float vSprite;
     varying float vOpacity;
+    //varying float heightRatio;
 
     void main() 
     {
+        
+        //const vec3 smokeColor = vec3(0.1,0.1,0.1); 
         vec2 texCoord = vec2(gl_PointCoord.x * 0.25 + vSprite, gl_PointCoord.y);
+        
+        
+        //vec3 mixColor = mix(color, smokeColor, 1.0);
+        
         gl_FragColor = vec4( texture2D( u_sampler, texCoord ).xyz * color * vOpacity, 1.0 );
+          
+         
     }
 `

+ 134 - 65
src/objects/fireParticle/smoke/SmokeParticle.js

@@ -19,20 +19,21 @@ const getTexture = ()=>{
 
 const defaults = 
 {
-    positionStyle    : Type.CUBE,
+    positions: [],
+    positionStyle    : "sphere",
     positionBase     : new THREE.Vector3( 0, 0, 0 ),
-     
+ 
     positionSpread   : new THREE.Vector3( 1, 1, 0), //cube
      
-    positionRadius   :     0,       // sphere
+    positionRadius   :   1,       // sphere
         
-    velocityStyle    : Type.CUBE,
+    velocityStyle    : 'cube',
      
-    velocityBase     : new THREE.Vector3( 0,  0,  15),     // cube
-    velocitySpread   : new THREE.Vector3( 0.8, 0.8, 0.5), 
+    velocityBase     : new THREE.Vector3( 0,  0,  1),     // cube  基础速度
+    velocitySpread   : new THREE.Vector3( 0.2, 0.2, -0.3), 
     
-    accelerationBase : 0.1,
-    accelerationSpread : 0.5,	
+    accelerationBase : 0.7,             //基础加速度
+    accelerationSpread : 1,	
     
     
     speedBase  : 0.1,       //sphere
@@ -41,31 +42,29 @@ const defaults =
     
 
     angleBase               : 0,
-    angleSpread             : 720,
-    angleVelocityBase       : 0,
-    angleVelocitySpread     : 720,
-    angleAccelerationBase   : 0,
-    angleAccelerationSpread : 0,
+    angleSpread             : 360,
+    angleVelocityBase       : 1,
+    angleVelocitySpread     : 30,
+    angleAccelerationBase   : 1,
+    angleAccelerationSpread : 5,
         
     sizeBase    :   0,  
     sizeSpread  :   0,
-    sizeTween    : new Tween( [0, 1], [3.2, 12.8] ),
+    sizeTween    : [[0, 0.3,   1], [0.3, 1.4,  3 ]], 
     
     
     colorBase   :   new THREE.Vector3(0.0, 1.0, 0.5), 
     colorSpread :   new THREE.Vector3(0.0, 0.0, 0.0),
-    colorTween   : new Tween( [0.4, 1], [ new THREE.Vector3(0,0,0.4), new THREE.Vector3(0, 0, 0.7) ] ),
+    colorTween   : new Tween( [0.4, 1], [ new THREE.Vector3(0,0,0.4), new THREE.Vector3(0, 0, 0.2) ] ),
 
     opacityBase     :   0.1,//1.0,
-    opacitySpread   :   0.3,
-    opacityTween : new Tween( [0.8, 2], [0.5, 0] ),
-    
-    
+    opacitySpread   :   0.2,
+    opacityTween :[ [0, 0.3,  0.7, 0.95, 1], [0, 0.1, 0.4 , 0.1, 0 ] ], 
      
-
-    particlesPerSecond : 20,
-    particleDeathAge   : 2.0,		
-    emitterDeathAge    : 60 // time (seconds) at which to stop creating particles.
+    //particlesPerSecond : 20,
+    density : 1,
+    particleDeathAge   : 1.5,		
+    //emitterDeathAge    : 60 // time (seconds) at which to stop creating particles.
 };
 
 const positions = [];
@@ -82,19 +81,17 @@ export default class SmokeParticle extends THREE.Points{
         this.particleArray = [];   
         this.blendStyle = THREE.NormalBlending; // false; 
         this.emitterAge = 0.0;
-        this.emitterAlive = true;
+        //this.emitterAlive = true;
        
-        
-        for ( var key in defaults ){
-            let value = prop[key] != void 0 ? prop[key] : defaults[ key ];	
+        prop = $.extend({}, defaults, prop)
+        for ( var key in prop ){
+            let value = prop[key] 
             if(value instanceof Array && value[0] instanceof Array ) this[ key ] = new Tween(...value)
             else this[ key ] = value
         }
-          
-        // How many particles could be active at any time?
-        this.particleCount = this.particlesPerSecond * Math.min( this.particleDeathAge, this.emitterDeathAge );
-    
+        this.curve = prop.curve
         
+        this.computeParams()
         this.createMaterial()
         this.createGeometry()
         
@@ -123,30 +120,23 @@ export default class SmokeParticle extends THREE.Points{
             if(state){//重新一个个放出粒子,否则会一股脑儿全部出来,因为同时大于粒子周期了一起重新生成出现。
                 setTimeout(()=>{//会先update一次delta为pageUnvisile的时间才触发
                     //归零
-                    console.log('归零')
-                    this.emitterAge = 0;
-                    
-                    this.geometry.dispose()
-                    
-                    this.createGeometry()
-                    
-
+                    //console.log('归零')
                     
+                    this.reStart()
                 },1) 
             }  
-        }) 
-        
-        
-        
-        
-        
+        })  
         
+    }
+
+    reStart(){
+        this.emitterAge = 0;
         
+        this.geometry.dispose()
         
+        this.createGeometry()  
     }
 
-   
-
     createMaterial(){
         this.material = new THREE.ShaderMaterial( 
         {
@@ -168,7 +158,21 @@ export default class SmokeParticle extends THREE.Points{
         
     }
 
-    createParticle()
+
+    computeParams(){  
+        this.density = 1
+        let length = (this.curve ? this.curve.wholeLength : 0) + this.positionRadius * 2 //加上首尾的半径
+        
+         
+        
+        let maxHeight = this.velocityBase.z * this.particleDeathAge + 0.5 * this.accelerationBase * this.particleDeathAge * this.particleDeathAge;//s = V0 * t + 0.5 * a * t*t ;     
+        this.particleCount =  Math.ceil( this.positionRadius * maxHeight * length * this.density  )  
+        this.particleCount = Math.max(5,this.particleCount)
+        
+        console.log('smoke  particleCount',this.particleCount)
+    }
+
+    createParticle(center)
     {
         var particle = new Particle({
             sizeTween : this.sizeTween,
@@ -176,24 +180,39 @@ export default class SmokeParticle extends THREE.Points{
             colorTween : this.colorTween,
         });
         particle.deathAge = this.particleDeathAge
+        particle.center = center
+         
         
-        
-        if (this.positionStyle == Type.CUBE)
+        if (this.positionStyle == 'cube')
             particle.position = this.randomVector3( this.positionBase, this.positionSpread ); 
-        if (this.positionStyle == Type.SPHERE)
+        if (this.positionStyle == 'sphere')
         {
-            var z = 2 * Math.random() - 1;
-            var t = 6.2832 * Math.random();
-            var r = Math.sqrt( 1 - z*z );
+            /* var z = 2 * Math.random() - 1    
+            var t = Math.PI * 2 * Math.random();
+            var r = Math.sqrt( 1 - z*z ) ;
             var vec3 = new THREE.Vector3( r * Math.cos(t), r * Math.sin(t), z );
             particle.position = new THREE.Vector3().addVectors( this.positionBase, vec3.multiplyScalar( this.positionRadius ) );
-        }
-            
-        if ( this.velocityStyle == Type.CUBE )
+           */
+            //怎么改半径
+            var y = 2 * Math.random() - 1    
+            var t = Math.PI * 2 * Math.random();
+            var r = Math.sqrt( 1 - y*y ) ;
+            var vec3 = new THREE.Vector3( r * Math.cos(t), y, r * Math.sin(t)  );
+            particle.position = new THREE.Vector3().addVectors( this.positionBase, vec3.multiplyScalar( this.positionRadius ) );
+          
+        } 
+         
+        particle.position.add(center)//add
+         
+         
+         
+         
+         
+        if ( this.velocityStyle == 'cube' )
         {
             particle.velocity     = this.randomVector3( this.velocityBase,     this.velocitySpread ); 
         }
-        if ( this.velocityStyle == Type.SPHERE )  
+        if ( this.velocityStyle == 'sphere' )  
         {
             //var direction = particle.position.clone()
             var direction = new THREE.Vector3(0,0,1) //烟应该都是向上的
@@ -219,12 +238,54 @@ export default class SmokeParticle extends THREE.Points{
         return particle;
     }			
 
+
+
     createGeometry(){
         this.geometry = new THREE.BufferGeometry()
+        var debugSphere = new THREE.Mesh(new THREE.SphereBufferGeometry(0.03, 5,5), new THREE.MeshBasicMaterial({color:'white',depthTest:false}))
+
+        let count, points;
+        if(this.positions.length>1){
+             
+            const spaceDis = 0.6;//间隔距离
+            
+            count = Math.ceil(this.curve.wholeLength / spaceDis) + 1 
+             
+            points = this.curve.getSpacedPoints( count );  
+            count = points.length
+            
+            points.forEach(e=>  { 
+                var sphere = debugSphere.clone();
+                sphere.position.copy(e)
+                viewer.scene.scene.add(sphere)
+            })
+            let haventGetPoints = points.slice() 
+            var getRanPoints = function(i){
+                var a = Math.random()
+                let choseIndex = Math.floor(haventGetPoints.length * a)
+                var point = haventGetPoints[choseIndex]
+                if(haventGetPoints.length == 1){
+                    haventGetPoints = points.slice()  
+                }else{
+                    haventGetPoints.splice(choseIndex, 1)
+                }
+                return point
+            }
+        }
+        
+        
+        
+        
+        
         for (var i = 0; i < this.particleCount; i++)
         {
+            var center = new THREE.Vector3().copy(this.positions.length>1 ? getRanPoints(i)  : this.positions[0])
+             
+            //var center = new THREE.Vector3().copy(this.positions.length>1 ? points[Math.floor(i/this.particleCount * count)] : this.positions[0])
+              
+             
             // remove duplicate code somehow, here and in update function below.
-            this.particleArray[i] = this.createParticle();
+            this.particleArray[i] = this.createParticle(center);
             positions[3*i] = this.particleArray[i].position.x
             positions[3*i+1] = this.particleArray[i].position.y
             positions[3*i+2] = this.particleArray[i].position.z
@@ -246,7 +307,13 @@ export default class SmokeParticle extends THREE.Points{
         this.geometry.setAttribute( 'customSize', new THREE.BufferAttribute( new Float32Array(sizes), 1 ) );
         this.geometry.setAttribute( 'customAngle', new THREE.BufferAttribute( new Float32Array(angles), 1 ) );
     }
-
+    
+    
+    updateGeometry(){ 
+        this.computeParams()
+        this.reStart() 
+        
+    }
     
 
     update(dt){
@@ -260,7 +327,7 @@ export default class SmokeParticle extends THREE.Points{
             if ( this.particleArray[i].alive )
             {
                   
-                if ( this.velocityStyle == Type.CUBE )
+                if ( this.velocityStyle == 'cube' )
                 {    
                     if(this.particleArray[i].age - this.particleArray[i].lastChangeVage > this.particleDeathAge*0.4  ){
                         if( Math.random()>0.3){//一定几率改变下方向
@@ -317,9 +384,11 @@ export default class SmokeParticle extends THREE.Points{
         // if no particles have died yet, then there are still particles to activate
         if ( this.emitterAge < this.particleDeathAge ) //开始时一个个放出来
         {
+            
+            let particlesPerSecond = this.particleCount / this.particleDeathAge
             // determine indices of particles to activate
-            var startIndex = Math.round( this.particlesPerSecond * (this.emitterAge +  0) );
-            var endIndex = Math.round( this.particlesPerSecond * (this.emitterAge + dt) );
+            var startIndex = Math.round( particlesPerSecond * (this.emitterAge +  0) );
+            var endIndex = Math.round( particlesPerSecond * (this.emitterAge + dt) );
             if  ( endIndex > this.particleCount ) 
                 endIndex = this.particleCount; 
                 
@@ -331,7 +400,7 @@ export default class SmokeParticle extends THREE.Points{
         for (var j = 0; j < recycleIndices.length; j++)
         {
             var i = recycleIndices[j];
-            this.particleArray[i] = this.createParticle();
+            this.particleArray[i] = this.createParticle(this.particleArray[i].center);
             this.particleArray[i].alive = 1.0; // activate right away
 
             positions[3*i] = this.particleArray[i].position.x
@@ -343,7 +412,7 @@ export default class SmokeParticle extends THREE.Points{
 
         // stop emitter?
         this.emitterAge += dt;
-        if ( this.emitterAge > this.emitterDeathAge )  this.emitterAlive = false;
+        //if ( this.emitterAge > this.emitterDeathAge )  this.emitterAlive = false;
     }
 
     randomValue(base, spread)

+ 257 - 0
src/objects/tool/CurveCtrl.js

@@ -0,0 +1,257 @@
+
+
+ 
+import * as THREE from "../../../libs/three.js/build/three.module.js";
+import {LineDraw} from "../../utils/DrawUtil";
+
+ 
+export default class CurveCtrl extends THREE.Object3D {
+    
+    constructor(points, material, color ){
+        super()
+        this.curve = new THREE.CatmullRomCurve3(points, false, "centripetal"    /* , tension */)
+        this.name = 'curveNode'        
+        this.material = material
+        this.createPath(); 
+        this.color = color;
+        this.handles = []; 
+        this.wholeLength = 0
+       /*  setTimeout(()=>{
+            
+            
+        })
+        
+        for(let i=0,j=this.points.length; i<j;i++){
+            this.handles.push[this.createHandle(this.points[i])]
+        }  */
+        this.visible_ = true
+        
+        
+        let updateHandles = ()=>{
+            this.updateHandles()
+        }
+        viewer.addEventListener("camera_changed", updateHandles)
+        
+        this.addEventListener('dispose', ()=>{ 
+            viewer.removeEventListener("camera_changed",  updateHandles)  
+            this.dispose()
+        })
+        
+    }
+    
+    
+    addPoint(position, index, ifUpdate){
+        let length = this.points.length 
+        
+        if(index === undefined){
+			index = length;
+		}
+        
+        let handle = this.createHandle(position);
+         
+        this.handles = [...this.handles.slice(0,index), handle, ...this.handles.slice(index,length)]
+      
+        this.points = [...this.points.slice(0,index), position, ...this.points.slice(index,length)]
+        
+        ifUpdate && this.updatePath()
+    
+    }
+    removePoint(index){
+        let handle = this.handles[index]
+        handle.svg.remove();
+        
+        this.handles.splice(index,1)
+        this.points.splice(index,1)
+        this.updatePath()
+    }
+    
+    createPath(){ 
+   
+        const line = LineDraw.createFatLine( [ ],this.material)
+        this.line = line;
+        this.add(line);
+    }
+    
+    
+    updatePath(){
+        let points 
+
+        this.wholeLength = this.points.reduce((total, currentValue, currentIndex, arr)=>{ //所有端点的距离总和
+            if(currentIndex == 0)return 0
+            return total + currentValue.distanceTo(arr[currentIndex-1]);
+        },0)
+        
+        if(this.points.length > 1){ 
+            const count = THREE.Math.clamp(Math.ceil(this.wholeLength * 5), 30, 500);
+            
+            points = this.curve.getSpacedPoints( count ); //得到的点不太均匀,两端容易点少。
+                   
+        }else{
+            points = [this.points[0], this.points[0]]
+        } 
+
+        LineDraw.updateLine(this.line, points)      
+        
+        
+        
+        
+    }
+    
+    
+    createHandle(position){
+		
+		const svgns = "http://www.w3.org/2000/svg";
+		const svg = document.createElementNS(svgns, "svg");
+
+		svg.setAttribute("width", "2em");
+		svg.setAttribute("height", "2em");
+		svg.setAttribute("position", "absolute");
+
+		svg.style.left = "50px";
+		svg.style.top = "50px";
+		svg.style.position = "absolute";
+		svg.style.zIndex = "10000";
+        svg.style.cursor = 'grab'
+        svg.style.transform = 'translate(-50%,-50%)'
+        
+		const circle = document.createElementNS(svgns, 'circle');
+		circle.setAttributeNS(null, 'cx', "1em");
+		circle.setAttributeNS(null, 'cy', "1em");
+		circle.setAttributeNS(null, 'r', "0.5em");
+		circle.setAttributeNS(null, 'style', 'fill: '+this.color+'; stroke: black; stroke-width: 0.2em;' );
+		svg.appendChild(circle);
+
+
+		const element = viewer.renderer.domElement.parentElement;
+		element.appendChild(svg);
+
+
+		const startDrag = (evt) => {
+			this.selectedElement = svg;
+
+			document.addEventListener("mousemove", drag);
+		};
+
+		const endDrag = (evt) => {
+			this.selectedElement = null;
+
+			document.removeEventListener("mousemove", drag);
+		};
+
+		const drag = (evt) => {
+			if (this.selectedElement) {
+                let index = this.handles.indexOf(handle)
+                
+				evt.preventDefault();
+
+				const rect = viewer.renderer.domElement.getBoundingClientRect();
+
+				const x = evt.clientX - rect.x;
+				const y = evt.clientY - rect.y;
+
+				const {width, height} = viewer.renderer.getSize(new THREE.Vector2());
+				const camera = viewer.scene.getActiveCamera();
+				 
+                const projected = position.clone().project(camera);
+          
+
+				projected.x = ((x / width) - 0.5) / 0.5;
+				projected.y = (-(y - height) / height - 0.5) / 0.5;
+
+				const unprojected = projected.clone().unproject(camera);
+				position.set(unprojected.x, unprojected.y, unprojected.z);
+            
+                this.updateHandle(index)
+                this.updatePath()
+                
+                this.dispatchEvent({type:'dragCurvePoint'})
+			}
+		};
+
+		svg.addEventListener('mousedown', startDrag);
+		svg.addEventListener('mouseup', endDrag);
+        svg.style.display = this.visible ? "" : "none" 
+        
+		const handle = {
+			svg: svg,
+		};
+        
+        this.addEventListener('dispose',()=>{
+            svg.removeEventListener('mousedown', startDrag);
+            svg.removeEventListener('mouseup', endDrag); 
+        })
+		return handle;
+	}
+    
+    
+    updateHandle(index){
+        if(!this.visible)return
+        
+        let handle = this.handles[index]
+        var position = this.points[index]
+        
+        var p = Potree.Utils.getPos2d(position, viewer.scene.getActiveCamera(), viewer.renderArea, viewer.mainViewport);
+        if(!p.trueSide){
+            handle.svg.style.display = 'none';  return;
+        }
+        handle.svg.style.left =  p.posInViewport.x  
+        handle.svg.style.top = p.posInViewport.y 
+          
+        
+         
+        handle.svg.style.display = ''
+            
+    }
+    
+    updateHandles(){
+        
+        this.handles.forEach((handle,index)=>{
+            this.updateHandle(index) 
+        }) 
+    }
+    
+    update(){
+        this.updateHandles()
+        this.updatePath()
+    }
+    
+    set visible(v){ 
+        if(v != this.visible_ ){
+            this.visible_ = v 
+            this.visible = v 
+            if(this.handles){
+                this.handles.forEach(e=>e.svg.style.display = v ? "" : "none" )
+                if(v) this.updateHandles() //因为不可见时没更新位置
+            }
+        }
+    }
+    get visible(){
+        return this.visible_
+    }  
+    
+    
+    /* set visible(v){ 
+        this.handles.forEach(e=>e.svg.style.display = v ? "" : "none" )
+        if(v) this.updateHandles() //因为不可见时没更新位置
+    } */
+    get points(){
+        return this.curve.points;
+    }
+    set points(points){
+        this.curve.points = points
+    }
+    getPointAt(t){
+        return this.curve.getPointAt(t)
+    }
+    getSpacedPoints(t){
+        return this.curve.getSpacedPoints(t)
+    }
+    dispose(){
+        this.parent.remove(this);
+        
+        this.handles.forEach(e=>e.svg.remove() )
+        
+        this.line.geometry.dispose()
+        
+    }
+}

+ 11 - 29
src/objects/tool/Measure.js

@@ -299,10 +299,7 @@ export class Measure extends ctrlPolygon{
         
         let edge
 		{ // edges 
-            edge = LineDraw.createFatLine( [
-					0, 0, 0,
-					0, 0, 0,
-			],{material:this.getLineMat('edgeDefault')} ) 
+            edge = LineDraw.createFatLine( [ ],{material:this.getLineMat('edgeDefault')} ) 
             viewer.setObjectLayers(edge, 'measure' )   
             
 		}
@@ -489,7 +486,7 @@ export class Measure extends ctrlPolygon{
     dispose(){//add
         var labels = this.edgeLabels.concat(this.coordinateLabels)
         this.areaLabel && labels.push(this.areaLabel)
-        labels.forEach(e=>e.dispose())
+        labels.forEach(e=>e.dispatchEvent({type:'dispose'}))
         super.dispose()
     }
     
@@ -571,26 +568,17 @@ export class Measure extends ctrlPolygon{
      
     
     createGuideLine(){//add 辅助线 
-        var guideLine = LineDraw.createFatLine([
-            0, 0, 0,
-            0, 0, 0,
-        ],{material:this.getLineMat('guide')} )
+        var guideLine = LineDraw.createFatLine([ ],{material:this.getLineMat('guide')} )
         guideLine.visible = false 
         this.guideLine = guideLine
         this.add(guideLine);
     }
     createHorVerGuideLine(){//创建水平与垂直辅助线,仅距离测量有。
-        var verGuideEdge = LineDraw.createFatLine([
-            0, 0, 0,
-            0, 0, 0,
-        ],{material:this.getLineMat('guide')} )
+        var verGuideEdge = LineDraw.createFatLine([ ],{material:this.getLineMat('guide')} )
         verGuideEdge.visible = false 
         this.verGuideEdge = verGuideEdge
         
-        var horGuideEdge = LineDraw.createFatLine([
-            0, 0, 0,
-            0, 0, 0,
-        ],{material:this.getLineMat('guide')} )
+        var horGuideEdge = LineDraw.createFatLine([ ],{material:this.getLineMat('guide')} )
         horGuideEdge.visible = false 
         this.horGuideEdge = horGuideEdge
         
@@ -1019,10 +1007,7 @@ function createCircleRadiusLine(){
 
 	const circleRadiusLine = new Line2(lineGeometry, lineMaterial);*/
 	
-    var circleRadiusLine = LineDraw.createFatLine([
-		0, 0, 0,
-		0, 0, 0,
-	],{
+    var circleRadiusLine = LineDraw.createFatLine([ ],{
         color:0xff0000,   
         dashSize: 0.5, 
 		gapSize: 0.2, 
@@ -1053,8 +1038,8 @@ function createCircleLine(){
 		);
 
 		coordinates.push(
-			...p0.toArray(),
-			...p1.toArray(),
+			 p0, 
+			 p1 
 		);
 	}
 
@@ -1098,10 +1083,7 @@ function createCircleLine(){
 
 function createLine(){
 	 
-    const line = LineDraw.createFatLine([
-		0, 0, 0,
-		0, 0, 0,
-	],{
+    const line = LineDraw.createFatLine([ ],{
         color: 0xff0000,
         dashSize: 0.5, 
 		gapSize: 0.2, 
@@ -1135,8 +1117,8 @@ function createCircle(){
 		);
 
 		coordinates.push(
-			...p0.toArray(),
-			...p1.toArray(),
+			 p0, 
+			 p1 
 		);
 	}
 

+ 2 - 2
src/objects/tool/ScreenBoxSelectTool.js

@@ -155,14 +155,14 @@ export class ScreenBoxSelectTool extends EventDispatcher{
                 }; 
                 
                  
-				let pointsNear = pointcloud.pick(viewer, volCam, ray, pickerSettings);
+				let pointsNear = pointcloud.pick(viewer, null, volCam, ray, pickerSettings);
 
 				volCam.rotateX(Math.PI);
 				volCam.updateMatrix();
 				volCam.updateMatrixWorld();
 				volCam.updateProjectionMatrix();
 				volCam.matrixWorldInverse.copy(volCam.matrixWorld).invert();
-				let pointsFar = pointcloud.pick(viewer, volCam, rayInverse, pickerSettings);
+				let pointsFar = pointcloud.pick(viewer,null, volCam, rayInverse, pickerSettings);
 
 				pointsNear && allPointsNear.push(...pointsNear);
 				pointsFar && allPointsFar.push(...pointsFar);

+ 16 - 9
src/objects/tool/ctrlPolygon.js

@@ -495,18 +495,25 @@ export class ctrlPolygon extends THREE.Object3D {
     removeMarker (index) {
         
 		this.points.splice(index, 1); 
-       
-		this.remove(this.markers[index]); 
+        
+        const marker = this.markers[index]
+		this.remove(marker); 
         this.markers.splice(index, 1);   
- 
-		let edgeIndex = index//(index === 0) ? 0 : (index - 1);
-		this.remove(this.edges[edgeIndex]);
-		this.edges.splice(edgeIndex, 1);
-  
+        marker.dispatchEvent({type:'dispose'})
+        
+        
+		let edgeIndex = index           //(index === 0) ? 0 : (index - 1);
+        const edge = this.edges[edgeIndex]
+        if(edge){
+            this.remove(edge);
+            this.edges.splice(edgeIndex, 1);
+            edge.dispatchEvent({type:'dispose'})
+        }
         this.point2dInfo && this.point2dInfo.points2d.splice(index, 1); //add
 
 
-		//this.update(); 
+		
+        
 	} 
     
     createAreaPlane(mat){ 
@@ -597,7 +604,7 @@ export class ctrlPolygon extends THREE.Object3D {
     
     dispose(){//add 
         this.parent.remove(this)
-         
+        this.markers.concat(this.edges).forEach(e=>e.dispatchEvent({type:'dispose'})) 
     }
     
     

+ 2 - 2
src/settings.js

@@ -111,7 +111,7 @@ const config = {//配置参数   不可修改
         fourViewportsMain:{//分四屏时防止卡顿
             maxLevelPercent: 0.8,  
             pointBudget :1*1000*1000, // 只要限制这个就足够 (为什么分屏focus区域不同会闪烁,navvis不会)(navvis:maxLevel:5,pointBudget:1*1000*1000)
-        }
+        }   
         ,
         low:{//highPerformance
             maxLevelPercent: 0.4, //最小为0
@@ -315,7 +315,7 @@ function getPrefix(){
  
 let settings = {//设置   可修改
     number: '', //场景序号
-    originDatasetId:'',//场景原本的数据集id
+    originDatasetId:'',//场景原本的数据集id,应该就是数据集第一个吧
     isOfficial:false,
     webSite:'data', //不同环境对应的静态文件的地址不同
     displayMode:'',

+ 54 - 143
src/start.js

@@ -51,134 +51,20 @@ var start = function(dom, mapDom, number, fileServer, webSite){ //t-Zvd3w0m
         Potree.datasetData = data
         viewer.transform = null
         var datasetLength = data.length 
-        var loaded = 0
-        var loadDone = function(){//点云cloud.js加载完毕后 
+        var pointcloudLoaded = 0
+        var panosLoaded = 0
+        var pointcloudLoadDone = function(){//点云cloud.js加载完毕后 
             viewer.updateModelBound()
             let {boundSize, center} = viewer.bound
            
             Potree.Log(`中心点: ${math.toPrecision(center.toArray(),2)}, boundSize: ${math.toPrecision(boundSize.toArray(),2)} ` , null, 12)
-            
-            if(!ifReload){
-                Potree.Images360Loader.load(viewer, {
-                    boundSize: boundSize.clone(),
-                    center: center.clone() 
-                },  images360 => {
-                    viewer.scene.add360Images(images360);
-               
-                    viewer.mapViewer.addListener(images360)
-                    
-                    {//初始位置
-                        
-                        var urlFirstView = false
-                        var panoId = browser.urlHasValue('pano',true);
-                        if(panoId != void 0){
-                            var pos
-                            var pano = viewer.images360.panos.find(e=>e.id==panoId);
-                            if(pano){
-                                viewer.images360.focusPano({
-                                    pano,
-                                    duration:0, 
-                                    callback:()=>{/* Potree.settings.displayMode = 'showPanos' */}
-                                })
-                                  
-                            }
-                        }
-                        
-                    }
-                    
-                    
-                    /* setTimeout(()=>{
-                        if( Potree.settings.number == 't-YLZ5XAALl7'  ||  't-e2Kb2iU' ){
-                             
-                            let transform = {
-                                't-YLZ5XAALl7' : {
-                                    rotation : [0,  0,    0.002326740152215126],
-                                    position : [0.421017820930033,   -0.22730084679456727,   0.0068952417582]
-                                },
-                                't-e2Kb2iU' : {
-                                    rotation : [0.06595546058095993,  -0.026986798620029413,  0.8429662590573239],
-                                    position : [ -502.6216232179794, 1051.5690392495885, 15.48490744053752]
-                                },
-                            }
-                             
-                            var path = `${Potree.resourcePath}/models/${Potree.settings.number}/`
-                            
-                            viewer.loadObj({ 
-                                objurl: path+'pipe.obj',
-                                mtlurl: path+'pipe.mtl',
-                                transform : transform[Potree.settings.number]
-                            })
-                        } 
-                    },1000) */
-                    if(number == 't-CwfhfqJ'){
-                        let position = Potree.Utils.datasetPosTransform({
-                            pointcloud:viewer.scene.pointclouds[0], 
-                            position: new THREE.Vector3(4.4318,-0.580291847759, -0.78),
-                            fromDataset:true 
-                        }) 
-                        
-                        viewer.modules.ParticleEditor.addParticle( {
-                             type:'fire',
-                             position,
-                             fireRadius:0.42, 
-                        })
-                        viewer.modules.ParticleEditor.addParticle( {
-                             type:'smoke',
-                             position: new THREE.Vector3().addVectors(position,new THREE.Vector3(0,0,0.3)),
-                             positionStyle : 2 ,  /* velocityStyle:2,  */
-                             positionRadius : 0.3,                        
-                             sizeTween: [[0, 0.3, 0.9, 1], [0.05, 0.1,  1,   0.8]],
-                             opacityBase : 0.2,
-                             opacityTween :[ [0, 0.3,  0.7, 0.95], [0, 0.2, 1 , 0.1, 0] ], 
-                             velocityBase     : new THREE.Vector3( 0,  0,  1),
-                             velocitySpread   : new THREE.Vector3( 0.2, 0.2, -0.3), 
-                             accelerationBase : 0.2,
-                             accelerationSpread : 0.7,	
-                             
-                             particlesPerSecond : 30,
-                             particleDeathAge   : 3.0,                         
-                        })
-                        
-                        viewer.modules.ParticleEditor.addParticle( {
-                             type:'explode',
-                             name:'fire splash',
-                             position: new THREE.Vector3().addVectors(position,new THREE.Vector3(0,0,0.3)), 
-                             size: 0.1,
-                            sizeRange: 0.3,
-                            sizeTween:[[0, 0.05, 0.3, 0.45], [0, 0.02, 0.1, 0.05] ],
-                            speed : 1,            //sphere
-                            speedRange : 4,
-                            positionRadius: 0.1,
-                            acceleration : 0.3,         
-                            accelerationRange : 1,
-                            
-                            particlesPerSecond:40,
-                        })
-                    }
-                    
-                    viewer.emit('allLoaded')
-                });
-                
-            }
             Potree.loadMapEntity() //加载floorplan,不一定成功 
-            
-            if(!ifReload){
+            if(!ifReload){   
                 viewer.scene.view.setView(//position, target
                     center.clone().add(new THREE.Vector3(10,5,10)), 
                     center
                 )
-                
-                //if(!Potree.settings.isOfficial){
-                /* if(number == 't-e2Kb2iU') {   
-                    setTimeout(//暂时延迟,等focus第一个点之后
-                        ()=>{
-                            viewer.loadProject(Potree.scriptPath + "/data/"+ number +"/potree.json5", ()=>{
-                                viewer.scene.cameraAnimations[0].play()
-                            })  
-                        },
-                    3000) 
-                }  */  
-                
+                 
                 viewer.dispatchEvent({type:'loadPointCloudDone'})
             
                 if(!Potree.settings.UserPointDensity){
@@ -188,13 +74,40 @@ var start = function(dom, mapDom, number, fileServer, webSite){ //t-Zvd3w0m
                 
                 Potree.Log('loadPointCloudDone  点云加载完毕', null, 10)
             }    
-             
-            
-            
             
         }
         
         
+        var panosLoadDone = function(){   
+            
+            
+            viewer.images360.loadDone() 
+            viewer.scene.add360Images(viewer.images360); 
+            viewer.mapViewer.addListener(viewer.images360)
+            
+            
+            {//初始位置 
+                var urlFirstView = false
+                var panoId = browser.urlHasValue('pano',true);
+                if(panoId != void 0){
+                    var pos
+                    var pano = viewer.images360.panos.find(e=>e.id==panoId);
+                    if(pano){
+                        viewer.images360.focusPano({
+                            pano,
+                            duration:0, 
+                            callback:()=>{/* Potree.settings.displayMode = 'showPanos' */}
+                        })
+                          
+                    }
+                } 
+            }
+            
+            viewer.addFire()
+            
+            console.log('allLoaded')
+            viewer.emit('allLoaded')
+        }
         
         var transformPointcloud = (pointcloud, dataset)=>{
             var locationLonLat = dataset.location.slice(0,2)
@@ -223,20 +136,12 @@ var start = function(dom, mapDom, number, fileServer, webSite){ //t-Zvd3w0m
             //viewer.mapView.showSources(false);  
         }
         
-        data.forEach((dataset,index)=>{
-            
-            //dataset.location = [ 113.60182446595765,22.364155116865753,0]
-            /* if(number == 't-e2Kb2iU') {    
-                dataset.orientation = 0
-            } */
-            
-            
+        data.forEach((dataset,index)=>{ 
             if(!viewer.transform){//拿任意一个数据集作为基准。它的位置就会是000  (第一个数据集应该一直就是初始数据集吧?)
                 var locationLonLat = dataset.location.slice(0,2)
                 proj4.defs("NAVVIS:TMERC", "+proj=tmerc +ellps=WGS84 +lon_0=" + locationLonLat[0].toPrecision(15) + " +lat_0=" + locationLonLat[1].toPrecision(15));
                 proj4.defs("WGS84", "+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs");
-                //proj4.defs("pointcloud", viewer.getProjection()); //不用从cloud里拿了
-            
+                 
                 let transform1 = proj4("WGS84", "NAVVIS:TMERC"); //这个ok  TMERC是展开的平面投影
                 let transform2 = proj4("+proj=tmerc +lat_0=0 +lon_0=123 +k=1 +x_0=500000 +y_0=0 +ellps=GRS80 +units=m +no_defs;");
                 
@@ -245,17 +150,17 @@ var start = function(dom, mapDom, number, fileServer, webSite){ //t-Zvd3w0m
                     lonlatToLocal : transform1,
                     lonlatTo4550 : transform2       // 转大地坐标EPSG:4550  
                 } 
-                // proj4(fromProjection, toProjection, coordinates)
-                //let transform = proj4("WGS84", "pointcloud");
+                
                 viewer.mapViewer && viewer.mapViewer.mapLayer.maps[0].updateProjection()
                 
             } 
             
             if(!ifReload){
-                var cloudPath = `https://${Potree.config.urls.prefix}/${Potree.settings.webSite}/${number}/data/${number}/webcloud/cloud.js` 
+                var datasetCode = dataset.sceneCode || dataset.name
+                var cloudPath = `https://${Potree.config.urls.prefix}/${Potree.settings.webSite}/${datasetCode}/data/${datasetCode}/webcloud/cloud.js` 
                 var timeStamp = dataset.createTime ? dataset.createTime.replace(/[^0-9]/ig,'') : '';  //每重算一次后缀随createTime更新一次 
                 
-                Potree.loadPointCloud(cloudPath, dataset.sceneCode || dataset.name , timeStamp, e => {
+                Potree.loadPointCloud(cloudPath, datasetCode , timeStamp, e => {
                     let scene = viewer.scene;
                     let pointcloud = e.pointcloud; 
                     let config = Potree.config.material
@@ -273,10 +178,17 @@ var start = function(dom, mapDom, number, fileServer, webSite){ //t-Zvd3w0m
                     pointcloud.panos = [] 
                     transformPointcloud(pointcloud,dataset)
                     scene.addPointCloud(pointcloud);
-                    loaded ++;
-                    if(loaded == datasetLength)loadDone()
+                    pointcloudLoaded ++;
+                    if(pointcloudLoaded == datasetLength)pointcloudLoadDone()
+                        
+                    Potree.loadPanos(dataset.id, (data) => {
+                        viewer.images360.addPanoData(data, dataset.id)
+                        panosLoaded ++; 
+                        if(panosLoaded == datasetLength){
+                            panosLoadDone() 
+                        } 
+                    })
                 })
-                
             }else{
                 let pointcloud = viewer.scene.pointclouds.find(p => p.dataset_id == dataset.id)
                 if(!pointcloud){
@@ -295,7 +207,7 @@ var start = function(dom, mapDom, number, fileServer, webSite){ //t-Zvd3w0m
         
         if(ifReload){ 
             
-            loadDone()
+            //loadDone()
         }
         
         
@@ -322,12 +234,11 @@ var start = function(dom, mapDom, number, fileServer, webSite){ //t-Zvd3w0m
     window.THREE = THREE
     window.buttonFunction = function(){
         /* 
-        viewer.startScreenshot({type:'measure', measurement:viewer.scene.measurements[0]})
-         */
+        viewer.startScreenshot({type:'measure', measurement:viewer.scene.measurements[0]}) 
         
         viewer.modules.RouteGuider.routeStart = new THREE.Vector3(0,0,-1.3)
         viewer.modules.RouteGuider.routeEnd = new THREE.Vector3(-10,0,-1.3)
-          
+       */
         
     }
 }

+ 24 - 5
src/utils.js

@@ -403,12 +403,18 @@ export class Utils {
 		
 		  
         if(viewport){ //转换到类似整个画面时
-            pickParams.x = mouse.x / viewport.width;
-            pickParams.y = renderer.domElement.clientHeight - mouse.y / viewport.height; 
+            
+             /*let mouseInViewport = Utils.convertNDCToScreenPosition(pointer, null, viewport.resolution.x, viewport.resolution.y)
+        
+            pickParams.x = mouseInViewport.x   //mouse.x / viewport.width;
+            pickParams.y = mouseInViewport.y //renderer.domElement.clientHeight - mouse.y / viewport.height;  */
+            pickParams.x = mouse.x;
+            pickParams.y = viewport.resolution.y - mouse.y;
         }else{ 
             pickParams.x = mouse.x;
             pickParams.y = renderer.domElement.clientHeight - mouse.y; 
-        }
+        } 
+         
         
 		
 
@@ -433,13 +439,18 @@ export class Utils {
                 e.material.pointSizeType = Potree.config.material.pointSizeType  
             }) 
             Potree.updatePointClouds(pointclouds,  camera, viewport.resolution );
+        }else{
+            if(viewer.viewports.filter(e=>!e.noPointcloud).length>1){
+                Potree.updatePointClouds(pointclouds,  camera, viewport.resolution ); //不加这句的话hover久了会不准 因node是错的
+            }
+            
         }
         
 		for(let pointcloud of pointclouds){ 
             
-			let point = pointcloud.pick(viewer, camera, ray, pickParams );
+			let point = pointcloud.pick(viewer, viewport, camera, ray, pickParams );
 			
-            viewport.afterRender
+          
             
 			if(!point){
 				continue;
@@ -1151,6 +1162,14 @@ Utils.convertScreenPositionToNDC = function(pointer, mouse, width, height) {
         pointer.y = 2 * -(mouse.y / height) + 1,
         pointer 
 }
+Utils.convertNDCToScreenPosition = function(pointer, mouse, width, height) { 
+    return mouse = mouse || new THREE.Vector2,
+        mouse.x = Math.round((pointer.x + 1 ) / 2 * width),
+        mouse.y = Math.round(-(pointer.y - 1 ) / 2 * height),
+        mouse 
+}
+
+
 
 Utils.getOrthoCameraMoveVec = function(pointerDelta, camera ){//获取当camera为Ortho型时 屏幕点1 到 屏幕点2 的三维距离
      

+ 90 - 81
src/utils/DrawUtil.js

@@ -43,6 +43,8 @@ var LineDraw = {
 		return line;  
 
 	},
+    
+    
 	moveLine: function (line, posArr) {
         if(posArr.length == 0)return
         let position = []
@@ -56,69 +58,7 @@ var LineDraw = {
         }
 	}  
 	,
-     /* 
      
-        为line创建用于检测鼠标的透明mesh,实际是个1-2段圆台。
-        由于近大远小的原因,假设没有透视畸变、创建的是等粗的圆柱的话, 所看到的线上每个位置的粗细应该和距离成反比。所以将圆柱改为根据距离线性渐变其截面半径的圆台,在最近点(相机到线的垂足)最细。如果最近点在线段上,则分成两段圆台,否则一段。
-      */
-	createBoldLine:function(points, o){ 
-		o = o || {}
-		var cylinder = o && o.cylinder;  
-		var CD = points[1].clone().sub(points[0]);
-		
-		var rotate = function(){//根据端点旋转好模型
-			cylinder.lastVector = CD;//记录本次的端点向量 
-			var AB = new THREE.Vector3(0,-1,0) 
-			var axisVec = AB.clone().cross(CD).normalize(); //得到垂直于它们的向量,也就是旋转轴
-			var rotationAngle = AB.angleTo(CD);
-			cylinder.quaternion.setFromAxisAngle( axisVec, rotationAngle ) 
- 		} 
-		if(o && o.type == "init"){
-			cylinder = new THREE.Mesh()
-			cylinder.material = o.mat 
-			if(CD.length() == 0)return cylinder;
-			rotate()
-		}
-		
-		if(CD.length() == 0)return cylinder;
-		if(o.type != "update"){
-			var CDcenter = points[0].clone().add(points[1]).multiplyScalar(.5);
-			cylinder.position.copy(CDcenter);
-			
-			if(!cylinder.lastVector || o.type == "moveAndRotate")rotate()
- 			else if(cylinder.lastVector &&  CD.angleTo(cylinder.lastVector)>0) rotate()//线方向改了or线反向了 重新旋转一下模型
- 			if(config.isEdit && !objects.mainDesign.editing )return cylinder;//节省初始加载时间?
-		}
- 
-		
-		//为了保证线段任何地方的可检测点击范围看起来一样大,更新圆台的结构(但是在镜头边缘会比中心看起来大)
-		var height = points[0].distanceTo(points[1]);
-		var standPos = o && o.standPos || objects.player.position;
-		var k = config.isMobile ? 20 : 40;
-		var dis1 = points[0].distanceTo(standPos);
-		var dis2 = points[1].distanceTo(standPos); 
-	 
-		var foot = math.getFootPoint(standPos, points[0], points[1]);//垂足
-		
-        if(o.constantBold || objects.player.mode != "panorama"){
-            var width = 0.1//0.08;
-            var pts = [new THREE.Vector2(width ,height/2),new THREE.Vector2(width ,-height/2)]  
-        }else if(foot.clone().sub(points[0]).dot( foot.clone().sub(points[1])   ) > 0){//foot不在线段上
-			var pts = [new THREE.Vector2(dis1 / k,height/2),new THREE.Vector2(dis2 / k,-height/2)]
-		}else{//在线段上的话,要在垂足这加一个节点,因它距离站位最近,而两端较远
-			var dis3 = foot.distanceTo(standPos); 
-			var len = foot.distanceTo(points[0])
-			var pts = [new THREE.Vector2(dis1 / k,height/2),  new THREE.Vector2(dis3 / k,height/2-len),  new THREE.Vector2(dis2 / k,-height/2)]
-		} 
-		cylinder.geometry && cylinder.geometry.dispose();//若不删除会占用内存
- 		cylinder.geometry = new THREE.LatheBufferGeometry( pts, 4/* Math.min(dis1,dis2)<10?4:3 */ )  
-		cylinder.renderOrder = 2;
-		
-		return cylinder;
-	},  
-	updateBoldLine:function(cylinder, points, type, standPos, constantBold){  
-		this.createBoldLine(points,{type:type,  cylinder : cylinder, standPos:standPos, constantBold}) //type:move:平移 会改长短  , type:update根据距离和角度更新  不改长短
-	},	 
 	 
 	createFatLineMat : function(o){ 
     
@@ -176,40 +116,47 @@ var LineDraw = {
         创建可以改变粗细的线。 
      */
 	createFatLine : function(posArr, o){  
-		var geometry = new LineGeometry();
-		geometry.setPositions( posArr );
+		var geometry = new LineGeometry(); 
 		geometry.setColors( o.color || [1,1,1]);
 
 		var matLine = o.material || this.createFatLineMat(o);
 		var line = new Line2( geometry, matLine );
 		//line.computeLineDistances();
-        
-        if(line.material.defines.USE_DASH != void 0){
-            //line.geometry.verticesNeedUpdate = true;
-            //line.geometry.computeBoundingSphere();
-            line.computeLineDistances(); 
-        }
-        
+         
 		line.scale.set( 1, 1, 1 );
 		line.renderOrder = 2;
+        
+        this.moveFatLine(line, posArr)
+        
 		return line;
 
 	},
+    
+    
+    
 	moveFatLine: function(line, posArr){
 		var geometry = line.geometry;
-		geometry.setPositions( [
-            ...posArr[0].toArray(), ...posArr[1].toArray(),  
-        ]);  
+        var positions = [];
+         
+        posArr.forEach(e=>{positions.push(...e.toArray())})
         
         
-        if(line.material.defines.USE_DASH != void 0){
-            //line.geometry.verticesNeedUpdate = true;
-            //line.geometry.computeBoundingSphere();
-            line.computeLineDistances(); 
+		if(positions.length > 0){
+            if(geometry.attributes.instanceEnd && geometry.attributes.instanceEnd.data.array.length != positions.length){//positions个数改变会有部分显示不出来,所以重建
+                geometry.dispose();
+                geometry = new LineGeometry();
+                line.geometry = geometry
+            }
+            geometry.setPositions( positions ) 
+            
+            if(line.material.defines.USE_DASH != void 0){
+                //line.geometry.verticesNeedUpdate = true; //没用
+                //line.geometry.computeBoundingSphere();
+                line.computeLineDistances(); 
+            } 
         }
         
         
-        
 	},
     
     updateLine: function(line, posArr){
@@ -218,8 +165,70 @@ var LineDraw = {
         }else{
             LineDraw.moveLine(line,posArr)
         }  
-    }
-    
+    },
+     /* 
+     
+        为line创建用于检测鼠标的透明mesh,实际是个1-2段圆台。
+        由于近大远小的原因,假设没有透视畸变、创建的是等粗的圆柱的话, 所看到的线上每个位置的粗细应该和距离成反比。所以将圆柱改为根据距离线性渐变其截面半径的圆台,在最近点(相机到线的垂足)最细。如果最近点在线段上,则分成两段圆台,否则一段。
+      */
+	createBoldLine:function(points, o){ 
+		o = o || {}
+		var cylinder = o && o.cylinder;  
+		var CD = points[1].clone().sub(points[0]);
+		
+		var rotate = function(){//根据端点旋转好模型
+			cylinder.lastVector = CD;//记录本次的端点向量 
+			var AB = new THREE.Vector3(0,-1,0) 
+			var axisVec = AB.clone().cross(CD).normalize(); //得到垂直于它们的向量,也就是旋转轴
+			var rotationAngle = AB.angleTo(CD);
+			cylinder.quaternion.setFromAxisAngle( axisVec, rotationAngle ) 
+ 		} 
+		if(o && o.type == "init"){
+			cylinder = new THREE.Mesh()
+			cylinder.material = o.mat 
+			if(CD.length() == 0)return cylinder;
+			rotate()
+		}
+		
+		if(CD.length() == 0)return cylinder;
+		if(o.type != "update"){
+			var CDcenter = points[0].clone().add(points[1]).multiplyScalar(.5);
+			cylinder.position.copy(CDcenter);
+			
+			if(!cylinder.lastVector || o.type == "moveAndRotate")rotate()
+ 			else if(cylinder.lastVector &&  CD.angleTo(cylinder.lastVector)>0) rotate()//线方向改了or线反向了 重新旋转一下模型
+ 			if(config.isEdit && !objects.mainDesign.editing )return cylinder;//节省初始加载时间?
+		}
+ 
+		
+		//为了保证线段任何地方的可检测点击范围看起来一样大,更新圆台的结构(但是在镜头边缘会比中心看起来大)
+		var height = points[0].distanceTo(points[1]);
+		var standPos = o && o.standPos || objects.player.position;
+		var k = config.isMobile ? 20 : 40;
+		var dis1 = points[0].distanceTo(standPos);
+		var dis2 = points[1].distanceTo(standPos); 
+	 
+		var foot = math.getFootPoint(standPos, points[0], points[1]);//垂足
+		
+        if(o.constantBold || objects.player.mode != "panorama"){
+            var width = 0.1//0.08;
+            var pts = [new THREE.Vector2(width ,height/2),new THREE.Vector2(width ,-height/2)]  
+        }else if(foot.clone().sub(points[0]).dot( foot.clone().sub(points[1])   ) > 0){//foot不在线段上
+			var pts = [new THREE.Vector2(dis1 / k,height/2),new THREE.Vector2(dis2 / k,-height/2)]
+		}else{//在线段上的话,要在垂足这加一个节点,因它距离站位最近,而两端较远
+			var dis3 = foot.distanceTo(standPos); 
+			var len = foot.distanceTo(points[0])
+			var pts = [new THREE.Vector2(dis1 / k,height/2),  new THREE.Vector2(dis3 / k,height/2-len),  new THREE.Vector2(dis2 / k,-height/2)]
+		} 
+		cylinder.geometry && cylinder.geometry.dispose();//若不删除会占用内存
+ 		cylinder.geometry = new THREE.LatheBufferGeometry( pts, 4/* Math.min(dis1,dis2)<10?4:3 */ )  
+		cylinder.renderOrder = 2;
+		
+		return cylinder;
+	},  
+	updateBoldLine:function(cylinder, points, type, standPos, constantBold){  
+		this.createBoldLine(points,{type:type,  cylinder : cylinder, standPos:standPos, constantBold}) //type:move:平移 会改长短  , type:update根据距离和角度更新  不改长短
+	},	
 }
 
 var MeshDraw = { 

+ 48 - 40
src/utils/SplitScreen.js

@@ -75,14 +75,8 @@ var SplitScreen = {
         
         
         
-        //材质
-        let material = viewer.scene.pointclouds[0].material
-        this.statesBefore = {
-            mat : {
-                colorType : material.activeAttributeName,
-                color : material.color.clone(),
-                opacity : material.opacity,
-            },
+        //材质 
+        this.statesBefore = { 
             pointDensity : Potree.settings.pointDensity,
             displayMode : Potree.settings.displayMode,
             
@@ -90,26 +84,37 @@ var SplitScreen = {
 			target: viewer.scene.view.getPivot(),
               
             //---
-            //ifShowMarker : Potree.settings.ifShowMarker,
-            
+            //ifShowMarker : Potree.settings.ifShowMarker, 
         }
         
+        viewer.setPointStandardMat(true) //切换到标准模式(主要为了mainViewport)
+        
+        var matBefore = { 
+            opacity : new Map()
+        } 
+         
+        viewer.scene.pointclouds.forEach(e=>{
+            matBefore.opacity.set(e, e.temp.pointOpacity) 
+            matBefore.colorType = e.material.activeAttributeName
+        }) 
         
         let beforeRender = function(viewport){
             viewer.scene.pointclouds.forEach(e=>{ 
                 if(viewport.name == "MainView"){ 
-                    e.material.activeAttributeName = SplitScreen.statesBefore.mat.colorType 
-                    //e.material.color = SplitScreen.statesBefore.mat.color
-                    e.material.useFilterByNormal = false
-                    //e.material.opacity = SplitScreen.statesBefore.mat.opacity 
+                    e.material.activeAttributeName = matBefore.colorType // 'rgba'
+                    
+                    e.material.useFilterByNormal = false 
+                    e.changePointOpacity(matBefore.opacity.get(e)) //1 //恢复下 e.temp.pointOpacity 其实就是1
+                    
                     Potree.settings.pointDensity = 'fourViewportsMain'/* 'fourViewports' */ //本来想比另外三屏高一点质量,结果发现会闪烁,因为点云加载需要时间 (navvis仿版也是一样,以后看看能否优化)
+                
                 }else{ 
                     e.material.activeAttributeName = "color"
-                    //e.material.color = e.color
-                    e.material.useFilterByNormal = true
-                    //e.material.opacity =  e.material.spacing    //0.09 //越稀疏给的opacity应该越高,支持超过1(隧道场景  spacing达9之多) 暂时去掉是因为opacity已经在别处算好了
+                    e.material.useFilterByNormal = true 
                     
                     Potree.settings.pointDensity = 'fourViewports' //强制降低点云质量
+                    e.changePointOpacity(0.5); 
+                     
                 }                 
             })  
         }
@@ -203,12 +208,7 @@ var SplitScreen = {
             }
         })
         
-        viewer.scene.pointclouds.forEach(e=>{ 
-            e.material.color.set(SplitScreen.statesBefore.mat.color)
-            e.material.activeAttributeName = SplitScreen.statesBefore.mat.colorType 
-            e.material.useFilterByNormal = false
-            e.material.opacity = SplitScreen.statesBefore.mat.opacity  
-        })
+        
         viewer.viewports = [viewer.mainViewport] 
         viewer.mainViewport.width = 1;
         viewer.mainViewport.height = 1;
@@ -227,12 +227,20 @@ var SplitScreen = {
          
         this.enableMap(true)
         this.enableFloorplan(true)
+         
+        Potree.settings.pointDensity = SplitScreen.statesBefore.pointDensity
+        Potree.settings.displayMode = SplitScreen.statesBefore.displayMode
         
         
+        viewer.scene.pointclouds.forEach(e=>{ 
+            //e.material.color.set(SplitScreen.statesBefore.mat.color)
+            //e.material.activeAttributeName = SplitScreen.statesBefore.mat.colorType 
+            e.material.useFilterByNormal = false
+            //e.material.opacity = SplitScreen.statesBefore.mat.opacity  
+        }) 
+        viewer.setPointStandardMat(false)
+         
         
-        
-        Potree.settings.pointDensity = SplitScreen.statesBefore.pointDensity
-        Potree.settings.displayMode = SplitScreen.statesBefore.displayMode
         //Potree.settings.ifShowMarker = SplitScreen.statesBefore.ifShowMarker
         //viewer.dispatchEvent({'type': 'finishSplitView' }) 
         viewer.updateScreenSize({forceUpdateSize:true}) 
@@ -287,7 +295,9 @@ var SplitScreen = {
     },
     
     setFloorplanDisplay: function(e, show=false){ 
-        viewer.updateVisible(e.floorplan.objectGroup, 'splitScreen', !!show)   
+        viewer.updateVisible(e.floorplan.objectGroup, 'splitScreen', !!show)  
+        
+        viewer.mapViewer.mapLayer.needUpdate = true
     },
     
      
@@ -303,24 +313,22 @@ var SplitScreen = {
         
     },
     enableFloorplan(enable){ //是否让自定义的平面图显示
-        let floorplan = viewer.mapViewer.mapLayer.maps.find(e=>e.name == 'floorplan')
+        let floorplans = viewer.mapViewer.mapLayer.maps.filter(e=>e.name.includes('floorplan'))
         if(!enable){ 
             //隐藏平面图
-            
-            if(floorplan){
-                //console.log('已经有floorplan')
-                this.setFloorplanDisplay({floorplan},false)
-            }else{ 
-                viewer.mapViewer.mapLayer.addEventListener( 'floorplanLoaded', this.setFloorplanDisplay ) //万一之后才加载 
-            }
+             
+            floorplans.forEach(floorplan=>this.setFloorplanDisplay({floorplan},false)) 
+              
+            viewer.mapViewer.mapLayer.addEventListener( 'floorplanLoaded', this.setFloorplanDisplay ) //万一之后才加载 
+             
         }else{
-            if(!floorplan){
-                //???
-            }else{
-                this.setFloorplanDisplay({floorplan},true)
-            }
+             
+            floorplans.forEach(floorplan=>this.setFloorplanDisplay({floorplan},true)) 
+            viewer.mapViewer.mapLayer.removeEventListener( 'floorplanLoaded', this.setFloorplanDisplay ) 
             
         }
+        
+        
         this.floorplanEnabled = enable
         this.updateMapViewerBG()
     },

+ 1 - 6
src/utils/math.js

@@ -89,12 +89,7 @@ var math = {
         i.y = -(i.y * o) + o,
         i
     },
-    convertScreenPositionToNDC: function(pointer, mouse, width, height) { 
-		return pointer = pointer || new THREE.Vector2,
-			pointer.x = mouse.x / width * 2 - 1,
-			pointer.y = 2 * -(mouse.y / height) + 1,
-			pointer 
-    },
+     
 	
 	handelPadResize:false,
 	/* handelPadding : function () { //去除player左边和上面的宽高,因为pc的player左上有其他element  许钟文

+ 17 - 19
src/viewer/PropertyPanels/CameraAnimationPanel.js

@@ -94,6 +94,7 @@ export class CameraAnimationPanel{
 				const elAdd = elNewKeyframe.find("input[name=add]");
 				elAdd.click( () => {
 					animation.createControlPoint(index);
+                    animation.changeCallback()
 				});
 
 				elKeyframes.append(elNewKeyframe);
@@ -121,23 +122,21 @@ export class CameraAnimationPanel{
 				const elMove = elKeyframe.find("img[name=move]");
 				const elDelete = elKeyframe.find("img[name=delete]");
 
-				elAssign.click( () => {
-					const cp = animation.controlPoints[index];
-
-					cp.position.copy(viewer.scene.view.position);
-					cp.target.copy(viewer.scene.view.getPivot());
+				elAssign.click( () => { 
+                    animation.posCurve.points[index].copy(viewer.scene.view.position);
+					animation.targetCurve.points[index].copy(viewer.scene.view.getPivot()); 
+                    animation.changeCallback()
+                     
 				});
 
-				elMove.click( () => {
-					const cp = animation.controlPoints[index];
-
-					viewer.scene.view.position.copy(cp.position);
-					viewer.scene.view.lookAt(cp.target);
+				elMove.click( () => {  
+					viewer.scene.view.position.copy(animation.posCurve.points[index]);
+					viewer.scene.view.lookAt(animation.targetCurve.points[index]); 
 				});
 
-				elDelete.click( () => {
-					const cp = animation.controlPoints[index];
-					animation.removeControlPoint(cp);
+				elDelete.click( () => { 
+					animation.removeControlPoint(index);
+                    animation.changeCallback()
 				});
 
 				elKeyframes.append(elKeyframe);
@@ -146,14 +145,13 @@ export class CameraAnimationPanel{
 			let index = 0;
 
 			addNewKeyframeItem(index);
-
-			for(const cp of animation.controlPoints){
-				
-				addKeyframeItem(index);
+  
+            animation.posCurve.points.forEach(e=>{
+                addKeyframeItem(index);
 				index++;
 				addNewKeyframeItem(index);
-
-			}
+            })
+            
 		};
 
 		updateKeyframes();

+ 11 - 3
src/viewer/map/Map.js

@@ -75,13 +75,21 @@ export class MapLayer extends EventDispatcher{ // 包括了 MapLayerBase SceneLa
             Potree.Log('平面图无数据','red')
             return
         }
-        var floorplan = new TiledMapFromEntity(this, this.tileColor, data[0] )//[0]?
+        var floorplan = new TiledMapFromEntity(this, this.tileColor, data[0]    )//[0]?
         this.addMap(floorplan)
         floorplan.updateProjection()
         floorplan.updateObjectGroup()
-        this.needUpdate = true
+        
         
         this.dispatchEvent({type:'floorplanLoaded', floorplan})
+        if(Potree.settings.floorplanEnable){
+            this.needUpdate = true
+        }else{
+            floorplan.setEnable(false)
+        }
+        
+        
+        return floorplan
     }
     
     addMap(t){ 
@@ -224,7 +232,7 @@ export class TiledMapBase extends EventDispatcher{
     set zoomLevel(zoomLevel){
         if(this._zoomLevel != zoomLevel){
             this._zoomLevel = zoomLevel
-            this.emit('zoomLevelChange',zoomLevel)
+            //this.emit('zoomLevelChange',zoomLevel)
              
             //if(this.name == 'map')console.log(zoomLevel,viewer.mapViewer.camera.zoom)
         }

+ 22 - 18
src/viewer/map/MapViewer.js

@@ -348,30 +348,29 @@ export class MapViewer extends ViewerBase{
     moveTo(endPosition, boundSize, duration=0, easeName){//前两个参数有xy即可
         endPosition = new THREE.Vector3(endPosition.x,endPosition.y,cameraHeight)
         
-        let endZoom, startZoom = this.camera.zoom
-        if(boundSize){
-            let aspect = boundSize.x / boundSize.y
-            let w, h; 
-            
-            if(this.camera.aspect > aspect){//视野更宽则用bound的纵向来决定
-                h = boundSize.y
-                //w = h * this.camera.aspect
-                endZoom = this.viewports[0].resolution.y / h
-            }else{
-                w = boundSize.x; 
-                //h = w / this.camera.aspect
-                endZoom = this.viewports[0].resolution.x / w
-            }  
-            //initCameraFeildWidth = w;
-        }
-        
+        let endZoom, startZoom = this.camera.zoom 
         
         //修改相机为bound中心,这样能看到全部(宽度范围内)
         
         this.view.setView(endPosition, null , duration,  ()=>{//done
              
         },(progress)=>{//onUpdate
-            if(boundSize){
+            if(boundSize){ 
+                let aspect = boundSize.x / boundSize.y
+                let w, h; 
+                
+                if(this.camera.aspect > aspect){//视野更宽则用bound的纵向来决定
+                    h = boundSize.y
+                    //w = h * this.camera.aspect
+                    endZoom = this.viewports[0].resolution.y / h
+                }else{
+                    w = boundSize.x; 
+                    //h = w / this.camera.aspect
+                    endZoom = this.viewports[0].resolution.x / w
+                }  
+                //onUpdate时更新endzoom是因为画布大小可能更改
+                
+                
                 this.camera.zoom = endZoom * progress + startZoom * (1 - progress)
                 this.camera.updateProjectionMatrix() 
             } 
@@ -566,6 +565,11 @@ export class MapViewer extends ViewerBase{
         
     }
     
+    
+    
+    
+    
+    
 }
 
 

+ 267 - 16
src/viewer/viewer.js

@@ -84,7 +84,9 @@ export class Viewer extends ViewerBase{
         
         this.testingMaxLevel = true
         
-        //add -------- 
+         
+        
+        
         this.navigateMode = 'free' // 'panorama'; 'free'自由模式是只显示点云或者未进入到漫游点, 
         this.isEdit = true
         this.waitQueue = []  
@@ -440,6 +442,9 @@ export class Viewer extends ViewerBase{
             this.modules.SiteModel.init()
             this.modules.Alignment.init()
             this.modules.ParticleEditor.init()
+            
+            
+            this.images360 = new Images360(this);
             //-----------
             
             
@@ -515,18 +520,18 @@ export class Viewer extends ViewerBase{
                     viewer.testNodeLevelTimer = setTimeout(()=>{//先加载一段时间最高level的点云。但希望不会刚好附近的点云都没有达到最高的level,否则就要走一段才能了。
                         viewer.testingMaxLevel = false
                         console.log('结束testingMaxLevel')
-                        //Potree.settings.pointDensity = Potree.settings.pointDensity 
+                        
                         this.setPointLevel()//重新计算
                     },3000) 
                     viewer.beginTestTime = Date.now()
                 }
-                //console.log('updateNodeMaxLevel ' +  pointcloud.dataset_id + " : "+ nodeMaxLevel)                
+                console.log('updateNodeMaxLevel ' +  pointcloud.dataset_id + " : "+ nodeMaxLevel)                
                 if(nodeMaxLevel >= 10 && viewer.testingMaxLevel){//10的时候差不多能加载到11和12了。假设最高只有12的话,就到10就可以。不过大多数场景都到不了10,也不知有没有大于10的,如果没有,这里可以写5.
                     viewer.testingMaxLevel = false
                     console.log('提前结束testingMaxLevel,用时:'+(Date.now()-viewer.beginTestTime))
                     //我的电脑用时大概1500
                 }
-                //Potree.settings.pointDensity = Potree.settings.pointDensity //重新计算
+                 
                 this.setPointLevel()//重新计算
                 
                 
@@ -572,6 +577,7 @@ export class Viewer extends ViewerBase{
     setPointLevel(){
         var pointDensity = Potree.settings.pointDensity
         var config = Potree.config.pointDensity[pointDensity];
+        if(!config)return
         this.scene.pointclouds.forEach(e=>{
             if(this.testingMaxLevel){
                 e.maxLevel = 12;//先加载到最大的直到测试完毕。由于5个level为一组来加载,所以如果写4最高能加载到5,如果写5最高能加载到下一个级别的最高也就是10
@@ -2112,7 +2118,7 @@ export class Viewer extends ViewerBase{
 				pointcloud.material.clipTask = this.clipTask;
 				pointcloud.material.clipMethod = this.clipMethod;
 			}
-		}
+		}  
 
 		{
 			for(let pointcloud of visiblePointClouds){
@@ -2156,7 +2162,9 @@ export class Viewer extends ViewerBase{
 
 	}
 
+ 
 
+ 
 
     updateViewPointcloud(camera, areaSize, isViewport){
         
@@ -2483,11 +2491,11 @@ export class Viewer extends ViewerBase{
                 
                 let scissorTest = view.width<1 || view.height<1
                 if(params_.target){
-                    params_.target.viewport.set(left, bottom, width, height);
-                    scissorTest && params_.target.scissor.set(left, bottom, width, height);
+                    params_.target.viewport.set(left, bottom, width, height);  
+                    scissorTest && params_.target.scissor.set(left, bottom, width, height); 
                     params_.target.scissorTest = scissorTest
                 }else{
-                    this.renderer.setViewport(left, bottom, width, height) //规定视口,影响图形变换 
+                    this.renderer.setViewport(left, bottom, width, height) //规定视口,影响图形变换(画布的使用范围) 
                     scissorTest && this.renderer.setScissor( left, bottom, width, height );//规定渲染范围
                     this.renderer.setScissorTest( scissorTest );//开启WebGL剪裁测试功能,如果不开启,.setScissor方法设置的范围不起作用 | width==1且height==1时开启会只有鼠标的地方刷新,很奇怪
                     
@@ -3382,6 +3390,42 @@ export class Viewer extends ViewerBase{
             this.images360.flyToPano(o)
         }else{
             this.scene.view.setView(o.position, o.target, o.duration, callback)
+        }  
+    }
+    
+    
+     
+    //设置点云为标准模式 
+    setPointStandardMat(state, pointDensity){
+        console.log('setPointStandardMat',state)
+        if(state){
+            if(this.pointStatesBefore){
+                return console.error('已设置过pointStatesBefore!')
+            }
+            this.pointStatesBefore = {opacity : new Map(), density:Potree.settings.pointDensity }
+            viewer.scene.pointclouds.forEach(e=>{
+                this.pointStatesBefore.opacity.set(e, e.temp.pointOpacity)  //因为更改pointDensity时会自动变opacity,所以这项最先获取
+                this.pointStatesBefore.colorType = e.material.activeAttributeName;
+            }) 
+            
+            if(pointDensity)Potree.settings.pointDensity = pointDensity //万一之后切换到全景模式怎么办 
+            
+            viewer.scene.pointclouds.forEach(e=>{   
+                e.material.activeAttributeName = 'rgba'; 
+                e.changePointOpacity(1) 
+            })
+        }else{
+            if(!this.pointStatesBefore){
+                return console.error('未设置过pointStatesBefore!')
+            }
+            if(pointDensity)Potree.settings.pointDensity = this.pointStatesBefore.pointDensity
+            
+            viewer.scene.pointclouds.forEach(e=>{   
+                e.material.activeAttributeName = this.pointStatesBefore.colorType
+                e.changePointOpacity(this.pointStatesBefore.opacity.get(e)) 
+            })
+            
+            this.pointStatesBefore = null
         }
         
         
@@ -3389,6 +3433,12 @@ export class Viewer extends ViewerBase{
     
     
     
+    
+    
+    
+    
+    
+    
     //调试时显示transformControl来调节object
     transformObject(object){
         if(!object.boundingBox){
@@ -3400,7 +3450,7 @@ export class Viewer extends ViewerBase{
     
      
     
-    addObjectTest1(){//加水管
+    /* addObjectTest1(){//加水管
         
         if(Potree.settings.number == 't-8KbK1JjubE'){
             
@@ -3419,7 +3469,7 @@ export class Viewer extends ViewerBase{
             var count = 0
             var addMesh = (color, path, height)=>{//height:在path之上的高度,负数代表在path之下
                 var name = 'cylinder'+count
-                var mat = new THREE.MeshStandardMaterial({color, /* wireframe:true, */ depthTest:false, roughness:0.4,metalness:0.5}) 
+                var mat = new THREE.MeshStandardMaterial({color,  depthTest:false, roughness:0.4,metalness:0.5}) 
                 let linePath = path.map(e=>new THREE.Vector3().copy(e).setZ(e.z+height))
                 let geo = MeshDraw.getExtrudeGeo( circlePts, null,{ extrudePath:linePath, tension:0.2}   )
                 var mesh = new THREE.Mesh(geo,mat);
@@ -3439,11 +3489,7 @@ export class Viewer extends ViewerBase{
             
             let linePath, height 
             
-            //地上管子 黄色
-            /* linePath = [{"x":-109.83,"y":-68.33,"z":-7.52},{"x":-95.17,"y":-59.3,"z":-7.38},  {"x":-38.75,"y":-24.01,"z":-6.01},{"x":0.5,"y":0.19,"z":-3.89},{"x":42.76,"y":26.88,"z":-1.03}
-               ,   {"x":44.27,"y":28.63,"z":-0.89},{"x":40.22,"y":35.37,"z":-0.67}// 拐弯向右 
-               ,    {"x":40.25,"y":36.47,"z":-0.6},{"x":38.69,"y":36.04,"z":18.04}// 拐弯向右 
-            ] */
+            //地上管子 黄色 
             linePath = [{"x":-109.83,"y":-68.33,"z":-7.52},{"x":-95.17,"y":-59.3,"z":-7.38},  {"x":-38.75,"y":-24.01,"z":-6.01},{"x":0.5,"y":0.19,"z":-3.89},{"x":39.29,"y":24.41,"z":-1.31}
                ,{"x":43.58,"y":27.7,"z":-0.97},{"x":40.22,"y":35.37,"z":-0.67}// 拐弯向右 
                ,   {"x":39.18,"y":36.71,"z":0.35},{"x":38.69,"y":36.04,"z":18.04} // 拐弯向上  
@@ -3465,7 +3511,7 @@ export class Viewer extends ViewerBase{
         
         
     }
-    
+     */
     
 
 
@@ -3542,10 +3588,215 @@ export class Viewer extends ViewerBase{
         
          
     }
+    
+    
+    
+        
+    addFire(){   
+  
+        if(Potree.settings.number == 't-CwfhfqJ'){
+            let position = Potree.Utils.datasetPosTransform({
+                pointcloud:viewer.scene.pointclouds[0], 
+                position: new THREE.Vector3(4.4318,-0.580291847759, -0.78),
+                fromDataset:true 
+            }) 
+            
+            viewer.modules.ParticleEditor.addParticle( {
+                 type:'fire',
+                 positions:[position],
+                 fireRadius:0.42, 
+                 fireHeight:10,
+            })
+             
+            viewer.modules.ParticleEditor.addParticle( {
+                 type:'smoke',
+                 positions: [ new THREE.Vector3().addVectors(position,new THREE.Vector3(0,0,0.3))],
+                 positionStyle : 'sphere' , 
+                 positionRadius : 0.3,                        
+                 sizeTween: [[0, 0.3, 0.9, 1], [0.05, 0.1,  1,   0.8]],
+                 opacityBase : 0.2,
+                 opacityTween :[ [0, 0.3,  0.7, 0.95, 1], [0, 0.2, 1 , 0.1, 0] ], 
+                 velocityBase     : new THREE.Vector3( 0,  0,  1),
+                 velocitySpread   : new THREE.Vector3( 0.2, 0.2, -0.3), 
+                 accelerationBase : 0.2,
+                 accelerationSpread : 0.7,	
+                 
+                 //particlesPerSecond : 30,
+                 particleDeathAge   : 3.0,                         
+            })
+            
+            viewer.modules.ParticleEditor.addParticle( {
+                 type:'explode',
+                 name:'fire splash',
+                 position: new THREE.Vector3().addVectors(position,new THREE.Vector3(0,0,0.3)), 
+                 size: 0.1,
+                sizeRange: 0.3,
+                sizeTween:[[0, 0.05, 0.3, 0.45], [0, 0.02, 0.1, 0.05] ],
+                opacityTween:  [[0, 0.05, 0.3, 0.45], [1, 1, 0.5, 0]] , 
+                speed : 1,            //sphere
+                speedRange : 4,
+                positionRadius: 0.1,
+                acceleration : 0.3,         
+                accelerationRange : 1,
+                
+                particlesPerSecond:40,
+            })
+        }
+    }
+
+
+        
+        
+        
+    
+    
+    
+    
+    
+    
+    
 };
 
 
 
 
 
+//------  CLIP  默认clipTask都是clipInside ----------------------
+/* 
+并集相当于加法,交集相当于加法。 所有结果都能展开成多个乘积相加。
+假设有4个clipBoxes,ABCD,   如果是  A*B + C*D ,那么这是最终结果。  如果是 (A+B)*(C+D) = A*C+A*D+B*C+B*D 
+ */
+ 
+let Clips = {
+    boxes : [],
+    unionGroups : [], //二维数组。最外层要求并集,里层要求交集(如果只有一个元素就是本身)。总结起来就是要求一堆交集的并集
+    shaderParams:{},
+    needsUpdate : true,
+
+    addClip(box, clipMethod){
+        //不允许重复
+        if(this.boxes.includes(box)){
+            return console.warn('addClip重复添加了box',box)
+        }
+        
+        boxes.push(box)
+        
+        if(clipMethod == 'any'){//并 
+            this.unionGroups.push([box])
+        }else if(clipMethod == 'all'){//交
+            this.unionGroups.forEach(mixGroup=>mixGroup.push(box))
+        }
+        this.needsUpdate = true
+    },
+    
+    removeClip(box){
+        if(!this.boxes.includes(box)){
+            return console.warn('removeClip没有找到该box',box)
+        }
+        var newGroups = [];
+        
+        this.unionGroups.forEach(mixGroup=>{
+            if(mixGroup.length == 1 && mixGroup[0] == box)return;//直接删除
+            newGroups.push(mixGroup.filter(e=>e!=box));
+        })
+        
+        this.unionGroups = newGroups;
+        this.needsUpdate = true
+    }
+    ,
+    
+    clearClip(){
+        this.boxes = [];
+        this.unionGroups = []
+        this.needsUpdate = true
+    }
+
+   
+    ,
+    
+    updateShaderParams(){//没写完 - - 见 pointcloud clip.vs
+        /*  
+        uniform mat4 clipBoxes[num_clipboxes]; 
+        uniform int clipBoxGroupCount; 
+        uniform int mixClipIndices[clipboxGroupItemCount]; //把所有的要求都直接放到数组内
+        */
+        
+        //这里需要转为Float32Array..? 参考material.setClipBoxes  
+        let everyClipGroupCount = this.unionGroups.map(e=>e.length)  
+        
+        let mixClipIndices = []
+        this.unionGroups.forEach(e=>{
+            mixClipIndices.push(...e)
+        })
+        
+        this.shaderParams = {
+            num_clipboxes : this.boxes.length,
+            clipBoxGroupCount : this.unionGroups.length,
+            everyClipGroupCount,
+            clipBoxIndexCount: mixClipIndices.length,
+            mixClipIndices
+        }
+        
+    } 
+    ,
+    getShaderParams(){//每次要传递参数到shader中,执行这个就好
+        if(this.needsUpdate){
+            this.updateShaderParams()
+        }
+        return this.shaderParams
+    }
+    
+    
+    
+    
+}
+ 
+
+
+
+
+
+/* setTimeout(()=>{
+    if( Potree.settings.number == 't-YLZ5XAALl7'  ||  't-e2Kb2iU' ){
+         
+        let transform = {
+            't-YLZ5XAALl7' : {
+                rotation : [0,  0,    0.002326740152215126],
+                position : [0.421017820930033,   -0.22730084679456727,   0.0068952417582]
+            },
+            't-e2Kb2iU' : {
+                rotation : [0.06595546058095993,  -0.026986798620029413,  0.8429662590573239],
+                position : [ -502.6216232179794, 1051.5690392495885, 15.48490744053752]
+            },
+        }
+         
+        var path = `${Potree.resourcePath}/models/${Potree.settings.number}/`
+        
+        viewer.loadObj({ 
+            objurl: path+'pipe.obj',
+            mtlurl: path+'pipe.mtl',
+            transform : transform[Potree.settings.number]
+        })
+    } 
+},1000)
+
+
+
+
+
+
+//if(!Potree.settings.isOfficial){
+  if(number == 't-e2Kb2iU') {   
+    setTimeout(//暂时延迟,等focus第一个点之后
+        ()=>{
+            viewer.loadProject(Potree.scriptPath + "/data/"+ number +"/potree.json5", ()=>{
+                viewer.scene.cameraAnimations[0].play()
+            })  
+        },
+    3000) 
+}   
+
+
+
+ */
 

+ 49 - 0
改bug的历史.txt

@@ -1,3 +1,52 @@
+
+
+
+
+
+
+
+
+
+2022-03-23
+四个屏的mainview中的reticule位置改变特别慢(intersect是错的)
+·四个屏都这个也一样  把beforeRender去掉也是  但是双屏不会
+·左上角 右下角屏也会了?!
+·在多个屏交替hover久一点就会明显  像卡顿
+·如果mianView以外的都active =  false 就正常。只要放出一个,就不正常
+·如果地图的noPointcloud没有一开始设置为false,双屏也会! 所以和点云渲染有关
+·如果没有hover到别的viewport就正常
+·会不会是nodes的切换问题
+·加了这句就行了Potree.updatePointClouds
+
+
+子问题:为什么pick截图保存到的是一整张图?而我自己改成pickState.renderTarget.scissor 这种绘制的就不会,但是清除也只清除当前区域了。
+·发现是因为之前绘制的没被清除,只有改变了画面才会清除。可是已经clear了呀。(猜测是因为这个关系所以会互相影响)
+·把clear提前到scissor之前就和原代码效果一致了 
+·但是改好了这个还是会,而且即便只刷新要读取的区域,也不影响才对。 
+
+
+
+
+
+
+
+
+
+
+2022-03-22
+为什么到另一个数据集cursor不准确。因为数据集不在000吗
+·单个数据集校准后也会,可能因为没更新node的matrixWorld(所以要在Alignment中就实时更新)
+	 见:node.sceneNode.matrixWorld.multiplyMatrices(pointcloud.matrixWorld, node.sceneNode.matrix);
+·方向就也不对 
+·是reticule的normal乘错了矩阵 
+
+
+
+
+
+
+
+
 2022-03-18
 出现过marker无法松开的情况(加载的数据),但是再选中房间又可以了
 ·是dropMarker时 因为有相同点 return continueDrag了