xzw преди 4 месеца
родител
ревизия
37e45ff450
променени са 3 файла, в които са добавени 510 реда и са изтрити 206 реда
  1. 443 177
      public/lib/potree/potree.js
  2. 1 1
      public/lib/potree/potree.js.map
  3. 66 28
      src/sdk/cover/index.js

+ 443 - 177
public/lib/potree/potree.js

@@ -15061,10 +15061,6 @@
 	  }
 	  toTreeNode(geometryNode, parent) {
 	    var node = new PointCloudOctreeNode();
-
-	    // if(geometryNode.name === "r40206"){
-	    //	console.log("creating node for r40206");
-	    // }
 	    var sceneNode = new Points(geometryNode.geometry, this.material);
 	    sceneNode.name = geometryNode.name;
 	    sceneNode.position.copy(geometryNode.boundingBox.min);
@@ -20391,6 +20387,7 @@
 	      b: 0,
 	      a: 1.0
 	    };
+	    this.textshadowColor = options.textshadowColor;
 	    this.borderColor = options.borderColor ? Common$1.CloneObject(options.borderColor) : {
 	      r: 0,
 	      g: 0,
@@ -20528,7 +20525,7 @@
 	        context.shadowOffsetX = 0;
 	        context.shadowOffsetY = 0;
 	        context.shadowColor = this.textshadowColor; //'red'
-	        context.shadowBlur = (this.textShadowBlur || this.fontSize / 3) * r;
+	        context.shadowBlur = (this.textShadowBlur || this.fontsize / 6) * r;
 	      }
 	      context.fillText(texts[i], x, y);
 	      var actualBoundingBoxDescent = infos[i].fontBoundingBoxDescent == void 0 ? this.fontsize * r * 0.2 : infos[i].fontBoundingBoxDescent;
@@ -21675,6 +21672,7 @@
 	    super();
 	    delete this.sceneBG;
 	    this.overlayScene = new Scene();
+	    this.overlayScene.name = 'overlay';
 	    viewer.addEventListener("render.pass.perspective_overlay", this.renderOverlay.bind(this));
 	    this.cameraP = new PerspectiveCamera(this.fov, 1, Potree.config.view.near, Potree.config.view.cameraFar);
 	    this.cameraO = new OrthographicCamera(-1, 1, 1, -1, Potree.config.view.near, Potree.settings.cameraFar);
@@ -22057,10 +22055,7 @@
 	};
 	Utils.getMousePointCloudIntersection = function (viewport, mouse, pointer, camera, viewer, pointclouds) {
 	  var pickParams = arguments.length > 6 && arguments[6] !== undefined ? arguments[6] : {};
-	  //getIntersectByDepthTex
-	  /* let result = viewer.edlRenderer.depthTexSampler.sample(viewport, mouse)//add
-	  if(result != 'unsupport')return result
-	    */
+	  //let startTime = performance.now() 
 
 	  if (!pointclouds || pointclouds.filter(e => Potree.Utils.getObjVisiByReason(e, 'datasetSelection')).length == 0) return;
 	  //console.log('getMousePointCloudIntersection')
@@ -22070,25 +22065,9 @@
 	    pickParams.x = Math.round(resolution.x / 2);
 	    pickParams.y = Math.round(resolution.y / 2);
 	  } else {
-	    /* if(viewport){ //转换到类似整个画面时 
-	        pickParams.x = mouse.x;
-	        pickParams.y = viewport.resolution.y - mouse.y;
-	    }else{ 
-	        pickParams.x = mouse.x;
-	        pickParams.y = renderer.domElement.clientHeight - mouse.y; 
-	    }  */
-
 	    pickParams.x = mouse.x;
 	    pickParams.y = resolution.y - mouse.y;
 	  }
-
-	  //console.log('getMousePointCloudIntersection')
-
-	  /* if(!raycaster){
-	      raycaster = new THREE.Raycaster();
-	      raycaster.setFromCamera(pointer, camera); 
-	  }  */
-
 	  var raycaster = new Raycaster();
 	  raycaster.setFromCamera(pointer, camera);
 	  var ray = raycaster.ray;
@@ -22206,6 +22185,9 @@
 	      _pointcloud4.visibleNodes = old_visibleNodes.get(_pointcloud4);
 	    }
 	  }
+
+	  //console.log('pick',   performance.now() - startTime )
+
 	  if (selectedPointcloud) {
 	    var localNormal = closestPoint.normal && new Vector3().fromArray(closestPoint.normal);
 	    return {
@@ -23027,7 +23009,7 @@
 	      var visible = insideFrustum;
 	      visible = visible && !(numVisiblePoints + node.getNumPoints() > Potree.pointBudget);
 	      visible = visible && !(numVisiblePointsInPointclouds.get(pointcloud) + node.getNumPoints() > pointcloud.pointBudget); // pointcloud.pointBudget一直是Infinity
-	      visible = visible && level <= maxLevel /* && level >= minLevel */; //< 改为 <=
+	      visible = visible && level <= maxLevel; //< 改为 <=
 	      //visible = visible || node.getLevel() <= 2;
 	      var pcWorldInverse = pointcloud.matrixWorld.clone().invert();
 	      /* let m = pcWorldInverse.elements 
@@ -23142,11 +23124,9 @@
 	        Potree.lru.touch(node.geometryNode); //在缓存中计入点云
 	        node.sceneNode.visible = true;
 	        node.sceneNode.material = pointcloud.material;
-
-	        /* level >= minLevel && */
-	        visibleNodes.push(node);
-	        /* level >= minLevel && */
-	        pointcloud.visibleNodes.push(node);
+	        var show = level >= minLevel && (!Potree.hideParentNode || node.children.some(e => !e || !e.isTreeNode())); //满子集且都加载好的不显示
+	        show && visibleNodes.push(node);
+	        show && pointcloud.visibleNodes.push(node);
 
 	        //if(Potree.settings.sortNodesDis){//add
 	        if (pointcloud.material.opacity < 1 && Potree.settings.notAdditiveBlending) {
@@ -25301,7 +25281,10 @@
 	    bg2: 17,
 	    layer1: 18,
 	    // 备用1
-	    layer2: 19 // 备用2
+	    layer2: 19,
+	    // 备用2
+
+	    dontIntersect: 20
 	  },
 	  renderOrders: {
 	    //会影响到绘制、pick时的顺序。
@@ -34054,6 +34037,9 @@
 	  judgeModelMat(object /* , isCurModel */) {
 	    if (!(Potree.settings.mergeType2 && Potree.settings.modelSkybox)) return;
 	    object.traverse(mesh => {
+	      if (mesh.isMonitor) return {
+	        stopContinue: true
+	      };
 	      if (mesh.material) {
 	        if (!mesh.materialOutside) {
 	          mesh.materialOutside = mesh.material;
@@ -39665,7 +39651,118 @@
 	    }
 	    this.material.activeAttributeName = Potree.settings.showClass && attributes.classification ? 'classification' : Potree.settings.showHotTemp && attributes.temp ? 'temp' : Potree.settings.showHotIr && attributes.ir ? 'ir' : Potree.settings.cloudAttributeName || 'rgba';
 	  }
+	  deepestNodeAt(position) {
+	    //改
+	    var startTime = performance.now();
+	    var toObjectSpace = this.matrixWorld.clone().invert();
+	    var objPos = position.clone().applyMatrix4(toObjectSpace);
+	    var current = this.root;
+	    while (true) {
+	      var containingChild = null;
+	      for (var child of current.children) {
+	        if (child !== undefined && !containingChild) {
+	          //
+	          if (child.getBoundingBox().containsPoint(objPos)) {
+	            containingChild = child;
+	          }
+	        }
+	      }
+	      if (containingChild !== null && containingChild instanceof PointCloudOctreeNode) {
+	        //如果是PointCloudOctreeGeometryNode可能geometry还没加载
+	        current = containingChild;
+	      } else {
+	        break;
+	      }
+	    }
+	    var deepest = current;
+	    console.log('deepestNodeAt', performance.now() - startTime);
+	    return deepest;
+	  }
+	  getNearestPoint(position, onlySearchLeaves) {
+	    //add 输入一个世界坐标,查找该点云中和它最近的点
+	    var startTime = performance.now();
+	    var inNode = this.deepestNodeAt(position);
+	    var toObjectSpace = this.matrixWorld.clone().invert();
+	    var objPos = position.clone().applyMatrix4(toObjectSpace); //该值记录一下,以后不改两点云相对位置直接用      
+	    var firstNode = inNode || this.root; //第一个搜寻点的node为所在node,初步找出最近点
+
+	    var nearest = firstNode.searchNearestPoint(position, {
+	      point: null,
+	      disSquare: Infinity
+	    });
+	    nearest.inNode = inNode === null || inNode === void 0 ? void 0 : inNode.name;
+
+	    //重新回到根结点向下找邻近node 
+	    var traverse = current => {
+	      if (current == firstNode || current.getBoundingBox().distanceToPoint(objPos) < nearest.dis) {
+	        onlySearchLeaves || current.searchNearestPoint(position, nearest); //搜寻当前节点
+	        var children = current.children.filter(e => e && e instanceof PointCloudOctreeNode);
+	        if (children.length) {
+	          for (var child of children) {
+	            if (child != firstNode) {
+	              traverse(child);
+	            }
+	          }
+	        } else {
+	          onlySearchLeaves && current.searchNearestPoint(position, nearest); //搜寻叶子节点
+	        }
+	      }
+	    };
+	    traverse(this.root);
+	    console.log('getNearestPoint', nearest, performance.now() - startTime);
+	  }
 	}
+	PointCloudOctreeNode.prototype.searchNearestPoint = function (pos) {
+	  var nearest = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {
+	    point: null,
+	    disSquare: Infinity
+	  };
+	  var positions = this.geometryNode.geometry.attributes.position;
+	  var tempPos = new Vector3();
+	  var toObjectSpace = this.sceneNode.matrixWorld.clone().invert();
+	  var objPos = pos.clone().applyMatrix4(toObjectSpace);
+	  var startTime = performance.now(),
+	    finded;
+	  for (var i = 0; i < positions.count; i++) {
+	    tempPos.fromArray(positions.array.slice(i * 3, i * 3 + 3));
+
+	    //let diff = new THREE.Vector3().subVectors(tempPos,objPos)
+	    if (nearest.dis != void 0 && !Potree.math.closeTo(tempPos, objPos, nearest.dis)) {
+	      //先筛除在xyz方向上的距离
+	      continue;
+	    }
+	    var d = tempPos.distanceToSquared(objPos);
+	    if (d < nearest.disSquare) {
+	      finded = true, nearest.point = tempPos, nearest.disSquare = d;
+	      nearest.dis == void 0 && (nearest.dis = Math.sqrt(nearest.disSquare)); //update
+	    }
+	  }
+	  if (finded) {
+	    nearest.dis = Math.sqrt(nearest.disSquare); //update
+	    nearest.point = tempPos.applyMatrix4(this.sceneNode.matrixWorld); //global pos
+	    nearest.nodeName = this.name;
+	  }
+	  console.log('node searchNearestPoint', this.name, performance.now() - startTime);
+	  //onlySearchLeaves开启后减少了10倍时间,但小概率不准,误差:    点云上的坐标 0.05m , 非点云上的0.1m
+	  return nearest;
+	};
+
+	/* 
+
+
+	搜索方A pointLoaded
+	    let tempPos = new THREE.Vector3
+	    let newAttri = ...
+	    for(let i=0;i<positions.count;i++){
+	        tempPos.set(positions[i*3], positions[i*3+1],positions[i*3+2]) 
+	        tempPos.applyMatrix4(this.matrixWorld)
+	        cloudB.getNearestPoint(tempPos)
+	    }
+
+
+
+
+	 */
 
 	class ProfileData {
 	  constructor(profile) {
@@ -61241,7 +61338,7 @@
 
 	    // CursorDeal
 	    this.lineDragPoint.addEventListener('mouseover', e => {
-	      setDragPointState(true);
+	      grabbingObject || setDragPointState(true);
 	    });
 	    this.lineDragPoint.addEventListener('mouseleave', e => {
 	      grabbingObject != 'lineDragPoint' && setDragPointState(false);
@@ -62182,12 +62279,13 @@
 	  vec3 = new Vector3(),
 	  quat1 = new Quaternion(),
 	  quat2 = new Quaternion();
-	var cameraModel;
+	var cameraModel, loadingCamModel;
 
 	//接收4dkk的监控 暂不支持修改   可以直接加到模型上,注意所附模型旋转90度后角度才对。
 	class Monitor extends Object3D {
 	  constructor(data, model) {
 	    super();
+	    this.isMonitor = true;
 	    warnHls();
 	    data.video = testUrl;
 	    this.data = data;
@@ -62264,26 +62362,28 @@
 	    });
 	    // 摄像头
 	    if (!cameraModel) {
-	      viewer.loadModel({
-	        fileType: 'glb',
-	        url: "".concat(Potree.resourcePath, "/models/glb/monitor.glb")
-	      }, model => {
-	        console.log('load monitor glb');
-	        this.cameraModel = model.children[0].children[0];
-	        this.cameraModel.geometry.translate(30, 50, -10);
-	        this.cameraModel.quaternion.setFromEuler(new Euler(Math.PI / 2, Math.PI, 0));
-	        this.obj3d.add(this.cameraModel);
-	        model.parent.remove(model);
-	        cameraModel = this.cameraModel.clone();
-	        this.modelLoaded();
-	      });
+	      if (!loadingCamModel) {
+	        loadingCamModel = true;
+	        viewer.loadModel({
+	          fileType: 'glb',
+	          url: "".concat(Potree.resourcePath, "/models/glb/monitor.glb")
+	        }, model => {
+	          cameraModel = model.children[0].children[0];
+	          cameraModel.geometry.translate(30, 50, -10);
+	          cameraModel.quaternion.setFromEuler(new Euler(Math.PI / 2, Math.PI, 0));
+	          cameraModel.name = 'cameraModel';
+	          console.log('load monitor glb', cameraModel.uuid);
+	          model.parent.remove(model);
+	          viewer.scene.monitors.forEach(e => e.modelLoaded());
+	          loadingCamModel = false;
+	        });
+	      }
 	    } else {
-	      this.cameraModel = cameraModel.clone();
-	      this.obj3d.add(this.cameraModel);
 	      this.modelLoaded();
 	    }
 	    this.updateAspect();
 	    {
+	      var group = new Shim.FollowRootObject(this); //透明有问题,只有放到overlayScene里渲染了
 	      this.titleLabel = new TextSprite$2({
 	        text: data.name,
 	        backgroundColor: {
@@ -62298,7 +62398,7 @@
 	          b: 255,
 	          a: 1
 	        },
-	        textshadowColor: '#888',
+	        textshadowColor: '#666',
 	        borderRadius: 2,
 	        fontsize: 34,
 	        renderOrder: 5,
@@ -62313,7 +62413,9 @@
 	      });
 	      this.titleLabel.sprite.material.depthTest = this.titleLabel.sprite.material.depthWrite = true;
 	      this.titleLabel.position.set(0, -0.2, 0.1);
-	      this.add(this.titleLabel);
+	      group.add(this.titleLabel);
+	      viewer.scene.overlayScene.add(group);
+	      group.name = 'monitorLabel';
 	    }
 	    {
 	      this.posOri = new Vector3(parseFloat(data.data['posOri-x']), parseFloat(data.data['posOri-y']), parseFloat(data.data['posOri-z'])), this.posOffset = new Vector3(parseFloat(data.data['posOffset-x']), parseFloat(data.data['posOffset-y']), parseFloat(data.data['posOffset-z'])),
@@ -62352,10 +62454,14 @@
 	    viewer.addEventListener('viewerResize', this.events.setSize);
 	    viewer.addEventListener('update', this.events.update);
 	    window.monitor = this;
-	    Potree.Utils.setObjectLayers(this, 'model');
+	    Potree.Utils.setObjectLayers(this, 'dontIntersect');
 	    Potree.Utils.setObjectLayers(this.cylinder.bottom, 'monitor');
+	    this.cameraModel && Potree.Utils.setObjectLayers(this.cameraModel, 'sceneObjects');
 	  }
 	  modelLoaded() {
+	    this.cameraModel = cameraModel.clone();
+	    this.cameraModel.material = cameraModel.material.clone();
+	    this.obj3d.add(this.cameraModel);
 	    this.cameraModel.addEventListener('mouseover', () => {
 	      CursorDeal.add('hoverMonitor');
 	      this.highlight(true);
@@ -69428,6 +69534,7 @@
 	    };
 	    this.addEventListener('isVisible', updatePlayInSight);
 	    this.addEventListener('transformChanged', updatePlayInSight);
+	    Potree.Utils.setObjectLayers(this, 'dontIntersect');
 	  }
 	  setContent(type, src, autoSize) {
 	    src = location.origin + '/' + src;
@@ -75852,13 +75959,15 @@
 	    this.transformControls.camera = viewer.viewports[0].camera;
 	    this.transformControls._gizmo.hideAxis = {
 	      translate: ['z'],
-	      rotate: ['x', 'y', 'z']
+	      rotate: ['x', 'y', 'z'],
+	      scale: ['x', 'y', 'z']
 	    };
 	    this.transformControls2.view = viewer.viewports[1].view;
 	    this.transformControls2.camera = viewer.viewports[1].camera;
 	    this.transformControls2._gizmo.hideAxis = {
 	      translate: ['x', 'y'],
-	      rotate: ['x', 'y', 'z']
+	      rotate: ['x', 'y', 'z'],
+	      scale: ['x', 'y', 'z']
 	    };
 	    this.secondCompass.changeViewport(viewer.viewports[0]);
 	    this.secondCompass.setDomPos();
@@ -75880,7 +75989,8 @@
 	    this.transformControls.camera = viewer.viewports[0].camera;
 	    this.transformControls.view = viewer.viewports[0].view;
 	    this.transformControls._gizmo.hideAxis = {
-	      rotate: ['e']
+	      rotate: ['e'],
+	      scale: ['x', 'y', 'z']
 	    };
 	    Potree.Utils.setObjectLayers(this.transformControls, 'sceneObjects'); //恢复
 
@@ -82151,7 +82261,7 @@
 
 	var tweens = {};
 	var maxClipFadeTime = Potree.settings.maxClipFadeTime; //渐变时间 s
-	var pathStates = new Map();
+	/* const pathStates = new Map */
 	//actions中可能包含没有动作的 如TPose
 
 	//包括无动画的模型在内的各项属性的过渡
@@ -82208,8 +82318,7 @@
 	    this.addKey(model, keyType, key);
 	  }
 	  at(time, delta, force) {
-	    var _this$camFollowObject,
-	      _this = this;
+	    var _this$camFollowObject;
 	    this.dispatchEvent({
 	      type: 'atTime',
 	      time
@@ -82229,107 +82338,256 @@
 	    var oldDisToCam = ((_this$camFollowObject = this.camFollowObject) === null || _this$camFollowObject === void 0 ? void 0 : _this$camFollowObject.length) == 1 && this.keepDistance && this.camFollowObject[0].boundCenter.distanceTo(viewer.mainViewport.view.position);
 	    var transitionRatio = 0.05 * delta * 60; //渐变系数,越小缓动程度越高,越平滑 //假设标准帧率为60fps,当帧率低时(delta大时) 降低缓动。速度快时缓动太高会偏移路径
 	    var transitionRatio2 = 0.8 * delta * 60;
-	    var _loop = function _loop() {
-	      //路径。开头结尾和别的衔接过渡
+
+	    /* for(let [model, keys] of this.pathKeys){//路径。开头结尾和别的衔接过渡
+	        let atPath //是否在path中 至多只有一个 
+	        let fadeToPath//是否在过渡到path中
+	        let fadeFromPath //是否从path中过渡到下一pose
+	        //以上三个权重越来越小,但都比pose大
+	        keys.find(key=>{
+	            if(key.path.points.length < 2) return
+	            let startToFade = key.time - maxClipFadeTime/2
+	            let endFade = key.time + key.dur + maxClipFadeTime/2
+	            atPath = time >= key.time && time <= key.time + key.dur
+	            if(atPath){
+	                atPath = key //找到一个就退出 
+	                return true
+	            }else if(delta!=void 0){ //有delta代表是播放时,要缓动,如果是点击时间轴到这一帧,就不缓动
+	                if(time > startToFade && time < key.time){
+	                    fadeToPath = key
+	                }else if(!fadeToPath && time > key.time + key.dur && time < endFade){
+	                    fadeFromPath = key
+	                }
+	            }
+	        })
+	        pathStates.set(model,{atPath,fadeToPath,fadeFromPath})
+	        
+	        
+	        if(atPath){//沿着curve行走,目视curve前方  (参照CameraAnimationCurve,搜quaFromCurveTan)
+	            let percent = THREE.Math.clamp((time - atPath.time) / atPath.dur, 0, 1)
+	            let {position , quaternion} = this.getPoseAtPathKey(atPath, percent)  //模型文件先保证其center在脚底,如果要我手动将bound底部对齐路径高度再说
+	            model.position.copy(position);
+	            quaternion && model.quaternion.copy(quaternion)  
+	        }else if(fadeToPath){ 
+	            let {position , quaternion} = this.getPoseAtPathKey(fadeToPath, 0)
+	            quaternion && lerp.quaternion(model.quaternion, quaternion)(transitionRatio) //每次只改变一点点  
+	            lerp.vector(model.position, position)(transitionRatio) 
+	        }
+	        
+	        if(atPath || fadeToPath){
+	            model.dispatchEvent('position_changed') //暂时都这么写,以后再判断是否真的改变了
+	            model.dispatchEvent('rotation_changed') 
+	        }
+	        
+	    }
+	    
+	    
+	    
+	    
+	    
+	    for(let [model, keys] of this.poseKeys){
+	           if(keys.length == 0) continue 
+	        let {atPath, fadeFromPath, fadeToPath} = pathStates.get(model) || {}
+	          
+	        tweens.scale = new Tween(keys.map(e=>e.time), keys.map(e=>e.scale)) 
+	        model.scale.copy(tweens.scale.lerp(time))
+	         
+	        if(!atPath && !fadeToPath){
+	            tweens.pos = new Tween(keys.map(e=>e.time), keys.map(e=>e.pos))
+	            tweens.qua = new Tween(keys.map(e=>e.time), keys.map(e=>e.qua))
+	            
+	            let time_ = time 
+	            if(fadeFromPath){  //但如果开始播放时模型已经在fadeFromPath这个区间里,也是直接过渡过去
+	                time_ = fadeFromPath.time + fadeFromPath.dur + maxClipFadeTime/2 //fadeTimeEnd
+	            }  
+	            let position = tweens.pos.lerp(time_)
+	            let quaternion = tweens.qua.lerp(time_)
+	            if(k){  
+	                lerp.quaternion(model.quaternion, quaternion)(transitionRatio) //每次只改变一点点  
+	                lerp.vector(model.position, position)(transitionRatio) 
+	            }else{
+	                if(this.poseTransition && delta!=void 0){
+	                    lerp.quaternion(model.quaternion, quaternion)(transitionRatio2) //每次只改变一点点  
+	                    lerp.vector(model.position, position)(transitionRatio2)  
+	                }else{
+	                    model.position.copy(position)
+	                    model.quaternion.copy(quaternion)
+	                }
+	                
+	            } 
+	            
+	        } 
+	       
+	        model.dispatchEvent('position_changed')
+	        model.dispatchEvent('rotation_changed') 
+	     
+	    }  */
+
+	    var posePathModels = [];
+	    [this.poseKeys, this.pathKeys /* , this.clipKeys */].forEach(map => {
+	      map.keys().forEach(model => {
+	        posePathModels.includes(model) || posePathModels.push(model);
+	      });
+	    });
+	    posePathModels.forEach(model => {
+	      var pathKeys = this.pathKeys.get(model);
+	      var poseKeys = this.poseKeys.get(model);
 	      var atPath; //是否在path中 至多只有一个 
-	      var fadeToPath; //是否在过渡到path中
-	      var fadeFromPath; //是否从path中过渡到下一pose
-	      //以上三个权重越来越小,但都比pose大
-	      keys.find(key => {
-	        if (key.path.points.length < 2) return;
-	        var startToFade = key.time - maxClipFadeTime / 2;
-	        var endFade = key.time + key.dur + maxClipFadeTime / 2;
-	        atPath = time >= key.time && time <= key.time + key.dur;
+	      var lastPath;
+	      var nextPath;
+	      if (pathKeys !== null && pathKeys !== void 0 && pathKeys.length) {
+	        pathKeys.find(key => {
+	          if (key.path.points.length < 2) return;
+	          var startToFade = key.time - maxClipFadeTime / 2;
+	          var endFade = key.time + key.dur + maxClipFadeTime / 2;
+	          atPath = time >= key.time && time <= key.time + key.dur;
+	          if (atPath) {
+	            atPath = key; //找到一个就退出 
+	            return true;
+	          }
+	          if (key.time + key.dur < time) lastPath = key;else if (key.time > time && !nextPath) nextPath = key;
+	        });
 	        if (atPath) {
-	          atPath = key; //找到一个就退出 
-	          return true;
-	        } else if (delta != void 0) {
-	          //有delta代表是播放时,要缓动,如果是点击时间轴到这一帧,就不缓动
-	          if (time > startToFade && time < key.time) {
-	            fadeToPath = key;
-	          } else if (!fadeToPath && time > key.time + key.dur && time < endFade) {
-	            fadeFromPath = key;
+	          //沿着curve行走,目视curve前方  (参照CameraAnimationCurve,搜quaFromCurveTan)  
+	          var percent = MathUtils.clamp((time - atPath.time) / atPath.dur, 0, 1);
+	          var {
+	            position,
+	            quaternion
+	          } = this.getPoseAtPathKey(atPath, percent, model); //模型文件先保证其center在脚底,如果要我手动将bound底部对齐路径高度再说
+	          model.position.copy(position);
+	          model.quaternion.copy(quaternion);
+	          model.dispatchEvent('position_changed'); //暂时都这么写,以后再判断是否真的改变了
+	          model.dispatchEvent('rotation_changed');
+	        } //pose关键帧加到路径上是无效的(scale除外)!
+	      }
+	      if (poseKeys) {
+	        tweens.scale = new Tween$1(poseKeys.map(e => e.time), poseKeys.map(e => e.scale));
+	        model.scale.copy(tweens.scale.lerp(time));
+	      } else {
+	        poseKeys = [];
+	      }
+	      if (!atPath) {
+	        poseKeys = poseKeys.slice();
+	        var addPathToPoseKey = (pathKey, percent) => {
+	          //把当前前后的path姿态加入帧
+	          var {
+	            position,
+	            quaternion
+	          } = this.getPoseAtPathKey(pathKey, percent, model);
+	          var fakeKey = {
+	            isPath: true,
+	            time: pathKey.time + pathKey.dur * percent,
+	            pos: position,
+	            qua: quaternion
+	          };
+	          var index = poseKeys.findIndex(e => e.time > fakeKey.time);
+	          if (index == -1) {
+	            index = poseKeys.length;
 	          }
-	        }
-	      });
-	      pathStates.set(model, {
-	        atPath,
-	        fadeToPath,
-	        fadeFromPath
-	      });
-	      if (atPath) {
-	        //沿着curve行走,目视curve前方  (参照CameraAnimationCurve,搜quaFromCurveTan)
-	        var percent = (time - atPath.time) / atPath.dur;
-	        var {
-	          position: _position,
-	          quaternion: _quaternion
-	        } = _this.getPoseAtPathKey(atPath, percent);
+	          poseKeys = [...poseKeys.slice(0, index), fakeKey, ...poseKeys.slice(index, poseKeys.length)];
+	        };
+	        lastPath && addPathToPoseKey(lastPath, 1);
+	        nextPath && addPathToPoseKey(nextPath, 0);
+	        tweens.pos = new Tween$1(poseKeys.map(e => e.time), poseKeys.map(e => e.pos));
+	        tweens.qua = new Tween$1(poseKeys.map(e => e.time), poseKeys.map(e => e.qua));
+	        var _position = tweens.pos.lerp(time);
+	        var _quaternion = tweens.qua.lerp(time);
 	        model.position.copy(_position);
-	        _quaternion && model.quaternion.copy(_quaternion);
-	      } else if (fadeToPath) {
-	        var {
-	          position: _position2,
-	          quaternion: _quaternion2
-	        } = _this.getPoseAtPathKey(fadeToPath, 0);
-	        _quaternion2 && lerp.quaternion(model.quaternion, _quaternion2)(transitionRatio); //每次只改变一点点  
-	        lerp.vector(model.position, _position2)(transitionRatio);
-	      }
-	      if (atPath || fadeToPath) {
-	        model.dispatchEvent('position_changed'); //暂时都这么写,以后再判断是否真的改变了
+	        model.quaternion.copy(_quaternion);
+	        model.dispatchEvent('position_changed');
 	        model.dispatchEvent('rotation_changed');
 	      }
-	    };
-	    for (var [model, keys] of this.pathKeys) {
-	      _loop();
-	    }
-	    for (var [_model, _keys] of this.poseKeys) {
-	      /* keys = keys.filter(e=>e.pos && e.scale && e.qua)*/
-	      if (_keys.length == 0) continue;
-	      var {
-	        atPath,
-	        fadeFromPath,
-	        fadeToPath
-	      } = pathStates.get(_model) || {};
-	      tweens.scale = new Tween$1(_keys.map(e => e.time), _keys.map(e => e.scale));
-	      _model.scale.copy(tweens.scale.lerp(time));
-	      if (!atPath && !fadeToPath) {
-	        tweens.pos = new Tween$1(_keys.map(e => e.time), _keys.map(e => e.pos));
-	        tweens.qua = new Tween$1(_keys.map(e => e.time), _keys.map(e => e.qua));
-	        var time_ = time;
-	        if (fadeFromPath) {
-	          //但如果开始播放时模型已经在fadeFromPath这个区间里,也是直接过渡过去
-	          time_ = fadeFromPath.time + fadeFromPath.dur + maxClipFadeTime / 2; //fadeTimeEnd
-	        }
-	        var position = tweens.pos.lerp(time_);
-	        var quaternion = tweens.qua.lerp(time_);
-	        if (fadeFromPath) {
-	          lerp.quaternion(_model.quaternion, quaternion)(transitionRatio); //每次只改变一点点  
-	          lerp.vector(_model.position, position)(transitionRatio);
-	        } else {
-	          if (this.poseTransition && delta != void 0) {
-	            lerp.quaternion(_model.quaternion, quaternion)(transitionRatio2); //每次只改变一点点  
-	            lerp.vector(_model.position, position)(transitionRatio2);
-	          } else {
-	            _model.position.copy(position);
-	            _model.quaternion.copy(quaternion);
-	          }
-	        }
-	      }
-	      _model.dispatchEvent('position_changed');
-	      _model.dispatchEvent('rotation_changed');
+	    });
+
+	    /* 
+	    for(let [model, keys] of this.pathKeys){//路径。开头结尾和别的衔接过渡
+	        
+	                keys.find(key=>{
+	            if(key.path.points.length < 2) return
+	            let startToFade = key.time - maxClipFadeTime/2
+	            let endFade = key.time + key.dur + maxClipFadeTime/2
+	            atPath = time >= key.time && time <= key.time + key.dur
+	            if(atPath){
+	                atPath = key //找到一个就退出 
+	                return true
+	            }  
+	            if(key.time + key.dur < time) lastPath = key
+	            else if(key.time > time && !nextPath) nextPath = key
+	             
+	        })
+	        pathStates.set(model,{atPath, lastPath, nextPath })
+	        
+	        
+	        if(atPath){//沿着curve行走,目视curve前方  (参照CameraAnimationCurve,搜quaFromCurveTan)
+	            let percent = THREE.Math.clamp((time - atPath.time) / atPath.dur, 0, 1)
+	            let {position , quaternion} = this.getPoseAtPathKey(atPath, percent, model)  //模型文件先保证其center在脚底,如果要我手动将bound底部对齐路径高度再说
+	            model.position.copy(position);
+	            model.quaternion.copy(quaternion)  
+	            model.dispatchEvent('position_changed') //暂时都这么写,以后再判断是否真的改变了
+	            model.dispatchEvent('rotation_changed') 
+	        } 
+	         
+	        
 	    }
-	    var _loop2 = function _loop2(_keys2) {
-	      if (_keys2.length == 0) return 1; // continue
-	      var weights = _keys2.map((key, i) => {
-	        var _keys3, _keys4;
+	    
+	    
+	    
+	    
+	    for(let [model, keys] of this.poseKeys){
+	              if(keys.length == 0) continue 
+	        let {atPath, lastPath, nextPath} = pathStates.get(model) || {}
+	          
+	        tweens.scale = new Tween(keys.map(e=>e.time), keys.map(e=>e.scale)) 
+	        model.scale.copy(tweens.scale.lerp(time))
+	        let pathToPoseKey = keys 
+	        if(!atPath ){
+	            keys = keys.slice()
+	            let addPathToPoseKey = (pathKey, percent)=>{ //把当前前后的path姿态加入帧
+	                let {position , quaternion} = this.getPoseAtPathKey(pathKey, percent, model)
+	                let fakeKey = {
+	                    isPath : true,
+	                    time: pathKey.time + pathKey.dur * percent,
+	                    pos:position , qua:quaternion
+	                } 
+	                let index = keys.findIndex(e=>e.time > pathKey.time) 
+	                if(index == -1){
+	                    index = keys.length
+	                } 
+	                keys = [...keys.slice(0,index), fakeKey, ...keys.slice(index,keys.length)]
+	            }
+	            lastPath && addPathToPoseKey(lastPath, 1)
+	            nextPath && addPathToPoseKey(nextPath, 0)
+	            
+	             
+	            tweens.pos = new Tween(keys.map(e=>e.time), keys.map(e=>e.pos))
+	            tweens.qua = new Tween(keys.map(e=>e.time), keys.map(e=>e.qua))
+	            
+	          
+	               let position = tweens.pos.lerp(time)
+	            let quaternion = tweens.qua.lerp(time)
+	            
+	            model.position.copy(position)
+	            model.quaternion.copy(quaternion)
+	        
+	            model.dispatchEvent('position_changed')
+	            model.dispatchEvent('rotation_changed') 
+	            
+	        } 
+	       
+	     
+	    }   */
+	    var _loop = function _loop(keys) {
+	      if (keys.length == 0) return 1; // continue
+	      var weights = keys.map((key, i) => {
+	        var _keys, _keys2;
 	        //计算每个动作权重(幅度)。  
 
 	        /* if(delta == void 0){//无缓动  但会造成和缓动时动作time不同
 	            return time >= key.time && time <= key.time + key.dur ? 1 : 0
 	        } */
 
-	        var fadeTimeStart = Math.min(maxClipFadeTime, key.dur, ((_keys3 = _keys2[i - 1]) === null || _keys3 === void 0 ? void 0 : _keys3.dur) || maxClipFadeTime) / 2; //过渡时间不超过当前和前一个的 half of dur
-	        var fadeTimeEnd = Math.min(maxClipFadeTime, key.dur, ((_keys4 = _keys2[i + 1]) === null || _keys4 === void 0 ? void 0 : _keys4.dur) || maxClipFadeTime) / 2; //过渡时间不超过当前和后一个的 half of dur
+	        var fadeTimeStart = Math.min(maxClipFadeTime, key.dur, ((_keys = keys[i - 1]) === null || _keys === void 0 ? void 0 : _keys.dur) || maxClipFadeTime) / 2; //过渡时间不超过当前和前一个的 half of dur
+	        var fadeTimeEnd = Math.min(maxClipFadeTime, key.dur, ((_keys2 = keys[i + 1]) === null || _keys2 === void 0 ? void 0 : _keys2.dur) || maxClipFadeTime) / 2; //过渡时间不超过当前和后一个的 half of dur
 
 	        var startTime1 = key.time - fadeTimeStart;
 	        var endTime1 = key.time + key.dur + fadeTimeEnd;
@@ -82341,7 +82599,7 @@
 	          //开始前维持第一个动作
 	          key.tempTime_ = 0;
 	          return 1;
-	        } else if (i == _keys2.length - 1 && time > endTime2) {
+	        } else if (i == keys.length - 1 && time > endTime2) {
 	          //所有动作播完后维持最后一个动作
 	          key.tempTime_ = Math.min(key.tempTime_, key.dur);
 	          return 1;
@@ -82360,7 +82618,7 @@
 	      }); //最多有两个>0的,在过渡 
 
 	      var animateActions = []; //在播的动作
-	      _keys2.forEach((key, i) => {
+	      keys.forEach((key, i) => {
 	        weights[i] > 0 && !animateActions.includes(key.action) && (animateActions.push(key.action), key.action.tempSW_ = {
 	          scale: 0,
 	          weight: 0,
@@ -82369,12 +82627,12 @@
 	      });
 	      //万一前后是一个动作…… 所以用tempSW_计算总值
 
-	      _keys2.forEach((key, i) => {
+	      keys.forEach((key, i) => {
 	        if (animateActions.includes(key.action)) {
 	          var weight = weights[i] * key.weight; //权重乘以自身幅度
 	          if (weight > 0) {
 	            key.action.play();
-	            key.action.paused = time != key.time || delta != void 0; //停在某帧 //如果没有点击该动作块的话 不停
+	            key.action.paused = true; /* time !=  key.time || delta != void 0 */ //停在某帧 //如果没有点击该动作块的话 不停
 
 	            key.action.tempSW_.time == null && (key.action.tempSW_.time = key.tempTime_); //相同动作优先用前一个的时间
 	            key.action.tempSW_.scale += key.speed; // * weights[i] //乘以weight在开始和结束作为缓动效果好,但是不好计算实时time
@@ -82392,31 +82650,31 @@
 
 	      //model.mixer.timeScale = 1 ;
 	    };
-	    for (var [_model2, _keys2] of this.clipKeys) {
-	      if (_loop2(_keys2)) continue;
+	    for (var [model, keys] of this.clipKeys) {
+	      if (_loop(keys)) continue;
 	    }
 	    {
 	      if (this.camFollowObject && !viewer.scene.monitors.some(e => e.isWatching)) {
 	        //in front of model 
 	        if (this.camFollowObject.length == 1) {
-	          var _model3 = this.camFollowObject[0];
+	          var _model = this.camFollowObject[0];
 	          if (viewer.images360.latestRequestMode == 'showPointCloud') {
 	            if (this.camFaceToObject) {
 	              var dis = 4;
 	              var dir = new Vector3(0, 0.1, 1).normalize(); //稍微朝上
-	              dir.multiplyScalar(dis).applyQuaternion(_model3.quaternion);
-	              var pos = new Vector3().addVectors(_model3.boundCenter, dir);
+	              dir.multiplyScalar(dis).applyQuaternion(_model.quaternion);
+	              var pos = new Vector3().addVectors(_model.boundCenter, dir);
 	              viewer.mainViewport.view.position.copy(pos);
-	              viewer.mainViewport.view.lookAt(_model3.boundCenter);
+	              viewer.mainViewport.view.lookAt(_model.boundCenter);
 	            } else if (this.keepDistance) {
 	              //不改镜头方向 保持一定角度。如果要改镜头方向,把lookAt提前
-	              viewer.mainViewport.view.position.subVectors(_model3.boundCenter, viewer.mainViewport.view.direction.clone().multiplyScalar(oldDisToCam));
+	              viewer.mainViewport.view.position.subVectors(_model.boundCenter, viewer.mainViewport.view.direction.clone().multiplyScalar(oldDisToCam));
 	              viewer.mainViewport.view.radius = oldDisToCam;
 	            } else {
-	              viewer.mainViewport.view.lookAt(_model3.boundCenter);
+	              viewer.mainViewport.view.lookAt(_model.boundCenter);
 	            }
 	          } else {
-	            viewer.mainViewport.view.lookAt(_model3.boundCenter);
+	            viewer.mainViewport.view.lookAt(_model.boundCenter);
 	          }
 	        } else {
 	          viewer.modules.MergeEditor.focusOn(this.camFollowObject, 0, true /* ,false,dirAve */);
@@ -82425,8 +82683,9 @@
 	    }
 	    viewer.dispatchEvent('content_changed');
 	  }
-	  getPoseAtPathKey(key, percent) {
-	    var percent2 = percent + 0.001;
+	  getPoseAtPathKey(key, percent, model) {
+	    var delta = 0.001;
+	    var percent2 = percent + delta;
 	    var curve = key.path.curve.clone();
 	    if (key.reverse) curve.points.reverse();
 	    var position = curve.getPointAt(percent);
@@ -82434,7 +82693,14 @@
 	    if (percent2 <= 1) {
 	      var position2 = curve.getPointAt(percent2);
 	      quaternion = math.getQuaFromPosAim(position2, position);
+	    } else {
+	      percent2 = percent - delta;
+	      var _position2 = curve.getPointAt(percent2);
+	      quaternion = math.getQuaFromPosAim(position, _position2);
 	    }
+	    //如果要将模型底部中心对准路径,需要先修改好模型scale ,然后boundingBox中心应用scale和qua, 加到position里
+	    //目前两个人物模型刚好模型pivot在脚底,如果是其他物体甚至直接用curve的朝向不太对,没有明确朝向。除非所有模型都保持上路径前的朝向
+	    //或者pos的z还用之前的
 	    return {
 	      position,
 	      quaternion
@@ -82497,11 +82763,11 @@
 	    for (var [model, keys] of this.poseKeys) {
 	      keys.length > 0 && (maxTime = Math.max(maxTime, keys[keys.length - 1].time));
 	    }
-	    for (var [_model4, _keys5] of this.clipKeys) {
-	      _keys5.length > 0 && (maxTime = Math.max(maxTime, _keys5[_keys5.length - 1].time + _keys5[_keys5.length - 1].dur));
+	    for (var [_model2, _keys3] of this.clipKeys) {
+	      _keys3.length > 0 && (maxTime = Math.max(maxTime, _keys3[_keys3.length - 1].time + _keys3[_keys3.length - 1].dur));
 	    }
-	    for (var [_model5, _keys6] of this.pathKeys) {
-	      _keys6.length > 0 && (maxTime = Math.max(maxTime, _keys6[_keys6.length - 1].time + _keys6[_keys6.length - 1].dur));
+	    for (var [_model3, _keys4] of this.pathKeys) {
+	      _keys4.length > 0 && (maxTime = Math.max(maxTime, _keys4[_keys4.length - 1].time + _keys4[_keys4.length - 1].dur));
 	    }
 	    this.duration = maxTime; //不算开始和结束动画的过渡时间的话
 
@@ -82626,7 +82892,7 @@
 	      poseKeys: {},
 	      clipKeys: {}
 	    };
-	    var _loop3 = function _loop3(model) {
+	    var _loop2 = function _loop2(model) {
 	      data.clipKeys[model.name] = keys.map(key => {
 	        return {
 	          actionIndex: model.actions.indexOf(key.action),
@@ -82638,10 +82904,10 @@
 	      });
 	    };
 	    for (var [model, keys] of this.clipKeys) {
-	      _loop3(model);
+	      _loop2(model);
 	    }
-	    for (var [_model6, _keys7] of this.poseKeys) {
-	      data.poseKeys[_model6.name] = _keys7.map(key => {
+	    for (var [_model4, _keys5] of this.poseKeys) {
+	      data.poseKeys[_model4.name] = _keys5.map(key => {
 	        return {
 	          qua: key.qua.toArray(),
 	          pos: key.pos.toArray(),
@@ -82654,11 +82920,11 @@
 	    return data;
 	  }
 	  buildFromData(data) {
-	    var _this2 = this;
+	    var _this = this;
 	    if (typeof data == 'string') {
 	      data = JSON.parse(data);
 	    }
-	    var _loop4 = function _loop4(name) {
+	    var _loop3 = function _loop3(name) {
 	      var model = viewer.objs.children.find(e => e.name == name);
 	      if (!model) {
 	        console.warn('没找到pose模型', name);
@@ -82672,12 +82938,12 @@
 	          time: e.time
 	        };
 	      });
-	      _this2.poseKeys.set(model, keys);
+	      _this.poseKeys.set(model, keys);
 	    };
 	    for (var name in data.poseKeys) {
-	      if (_loop4(name)) continue;
+	      if (_loop3(name)) continue;
 	    }
-	    var _loop5 = function _loop5(_name) {
+	    var _loop4 = function _loop4(_name) {
 	      var model = viewer.objs.children.find(e => e.name == _name);
 	      if (!model) {
 	        console.warn('没找到clip模型', _name);
@@ -82692,10 +82958,10 @@
 	          speed: e.speed
 	        };
 	      });
-	      _this2.clipKeys.set(model, keys);
+	      _this.clipKeys.set(model, keys);
 	    };
 	    for (var _name in data.clipKeys) {
-	      if (_loop5(_name)) continue;
+	      if (_loop4(_name)) continue;
 	    }
 	  }
 	  ifContainsModel(model) {
@@ -90201,7 +90467,7 @@
 	    var cameraLayers;
 	    if (params.cameraLayers) cameraLayers = params.cameraLayers;else {
 	      if (params.viewport.name == "mapViewport") cameraLayers = ['bothMapAndScene', 'light'];else {
-	        cameraLayers = ['sceneObjects', 'light', 'bothMapAndScene', 'monitor'];
+	        cameraLayers = ['sceneObjects', 'light', 'bothMapAndScene', 'monitor', 'dontIntersect'];
 	        if (!params.useModelOnRT) {
 	          cameraLayers.push('model');
 	        }

Файловите разлики са ограничени, защото са твърде много
+ 1 - 1
public/lib/potree/potree.js.map


+ 66 - 28
src/sdk/cover/index.js

@@ -647,7 +647,7 @@ export const enter = ({ dom, mapDom, isLocal, lonlat, scenes, laserRoot, laserOS
 
             return deferred.promise()
         },
-        getPose() {//获取当前点位和朝向
+        getPose(modelId) {//获取当前点位和朝向
             
             const camera = viewer.scene.getActiveCamera()
             const target = viewer.scene.view.getPivot().clone()
@@ -663,6 +663,12 @@ export const enter = ({ dom, mapDom, isLocal, lonlat, scenes, laserRoot, laserOS
  
             }
             
+            if(modelId){
+                pose.modelId2 = modelId
+                pose.posInModel2 = Potree.Utils.datasetPosTransform({ toDataset: true, position: camera.position.clone(), datasetId: modelId  })
+                pose.rotInModel2 = Potree.Utils.datasetRotTransform({ toDataset: true, quaternion: camera.quaternion.clone(), getQuaternion: true, datasetId: modelId }).toArray() //拿第一个数据集
+            }
+            
             //console.log('getPose',position, target)
             return pose
         },
@@ -673,7 +679,14 @@ export const enter = ({ dom, mapDom, isLocal, lonlat, scenes, laserRoot, laserOS
             //飞到某个点  
             
             let deferred = $.Deferred()
-            if(o.panoId != void 0){
+            
+            if (o.modelId2 != void 0) {//飞到热点
+                ['position', 'target'].forEach(e => { 
+                    if (o[e]) {
+                        o[e] = Potree.Utils.datasetPosTransform({ fromDataset: true, datasetId: o.modelId2, position: o[e] })
+                    }
+                })
+            }else if(o.panoId != void 0){
                 let model = o.model.model
                 let pano = model.panos.find(a=>a.originID == o.panoId)
                 if(pano){
@@ -700,7 +713,7 @@ export const enter = ({ dom, mapDom, isLocal, lonlat, scenes, laserRoot, laserOS
                     })
                 }
             }
-            
+        
            
             if (o.distance || o.maxDis) {
                 //o.isFlyToTag = true
@@ -1109,7 +1122,7 @@ export const enter = ({ dom, mapDom, isLocal, lonlat, scenes, laserRoot, laserOS
                     
                 },
 
-                moveModelTo(mouse, pos3d){//'移动到这里'
+                moveModelTo(mouse, pos3d){//'移动到这里'    //使模型中心底部的在鼠标所在位置
                     console.log('moveModelTo', mouse)
                     let viewport = viewer.mainViewport
                     if(!pos3d){
@@ -1117,12 +1130,12 @@ export const enter = ({ dom, mapDom, isLocal, lonlat, scenes, laserRoot, laserOS
                         let height = viewport.height * viewer.renderArea.clientHeight
                         let pointer = Potree.Utils.convertScreenPositionToNDC(null,  mouse, width, height);
                      
-                        let {x,y} = Potree.Utils.getPointerPosAtHeight(model.boundCenter.z, pointer)
-                        pos3d = new THREE.Vector3(x,y, model.boundCenter.z)
+                        let {x,y} = Potree.Utils.getPointerPosAtHeight(model.bound.min.z, pointer)
+                        pos3d = new THREE.Vector3(x,y, model.bound.min.z)
                     } 
                     
                     MergeEditor.moveBoundCenterTo(model, pos3d)  //使模型中心的xy在鼠标所在位置
-                     
+                    model.position.z += model.boundSize.z / 2
                     model.dispatchEvent({type:"position_changed", byControl:true}) 
                 },
 
@@ -1145,21 +1158,6 @@ export const enter = ({ dom, mapDom, isLocal, lonlat, scenes, laserRoot, laserOS
                         //console.log('changeSelect',  props.id, state)
                     }
                 },
-                changeScale(s) {
-                    if (model) {
-                        s /= 100
-
-                        if (model.scale.x == s) return
-                        //MergeEditor.history.beforeChange(model)//但不知道什么时候结束拖拽
-
-                        model.scale.set(s, s, s)
-                        model.isPointcloud && model.changePointSize(/* Potree.config.material.realPointSize * s */)
-
-                        model.dispatchEvent("scale_changed")
-                        
-
-                    }
-                },
                 changeOpacity(opacity) { //见笔记:透明物体的材质设置
                     if (opacity == void 0) opacity = 100
                     opacity /= 100
@@ -1169,6 +1167,24 @@ export const enter = ({ dom, mapDom, isLocal, lonlat, scenes, laserRoot, laserOS
                     /* model && MergeEditor.setModelBtmHeight(model,z)
                     model.dispatchEvent('transformChanged') //改了position */
                 },
+                changeScale(s) {
+                    if (model) {
+                        if(s.x != void 0){
+                            model.scale.copy(s) //animate model
+                        }else{
+                            s /= 100
+
+                            if (model.scale.x == s) return
+                            //MergeEditor.history.beforeChange(model)//但不知道什么时候结束拖拽
+
+                            model.scale.set(s, s, s)
+                            model.isPointcloud && model.changePointSize(/* Potree.config.material.realPointSize * s */)
+                        }
+                        model.dispatchEvent("scale_changed")
+                        
+
+                    }
+                }, 
                 changePosition(pos) {//校准取消时执行
                     //console.log('changePosition', model.name, pos.x, pos.y, pos.z) 
                     if(pos.x == 0 && pos.y == 0 && pos.z == 0 && model.lonLatPos ){
@@ -1494,7 +1510,7 @@ export const enter = ({ dom, mapDom, isLocal, lonlat, scenes, laserRoot, laserOS
                                 info.scale = (typeof data.scale == 'number') ? new THREE.Vector3(data.scale/100,data.scale/100,data.scale/100) : new THREE.Vector3().copy(data.scale)
                                 info.qua = new THREE.Quaternion().copy(data.quaternion)
                                 return info
-                            }
+                            } 
                             Object.assign(key, getData(frame.mat)) 
                             AnimationEditor.addKey(model, 'pose', key )
                             return {
@@ -1528,7 +1544,7 @@ export const enter = ({ dom, mapDom, isLocal, lonlat, scenes, laserRoot, laserOS
                                     //return console.error('cannot find action', key.key) 
                                     let random = Math.floor(Math.random() * (model.actions.length))
                                     random = Math.min(model.actions.length-1, random)
-                                    console.log('没找到动作暂时先用第'+ random +'个') 
+                                    console.log('没找到动作 '+key.key+', 暂时先用第'+ random +'个') 
                                     key.action = model.actions[random]
                                 }   
                                 delete key.amplitude
@@ -1537,6 +1553,23 @@ export const enter = ({ dom, mapDom, isLocal, lonlat, scenes, laserRoot, laserOS
                                 
                             AnimationEditor.addKey(model, 'clip', key)
                             
+                            let updateAction = ()=>{
+                                if(key.chosed && AnimationEditor.cursorTime == key.time){//如果选择了该动作且在开头,就直接播放原动作
+                                    model.actions.forEach(a=>{
+                                        if(a == key.action){
+                                            a.play()
+                                            a.paused = false
+                                            a.setEffectiveTimeScale(key.speed)
+                                            a.setEffectiveWeight(key.weight); 
+                                        }else{
+                                            a.stop()
+                                        }
+                                    })
+                                }else update()
+                            }
+                            
+                            
+                            
                             return {
                                 destroy(){ 
                                     AnimationEditor.removeKey(model,'clip', key)
@@ -1546,21 +1579,26 @@ export const enter = ({ dom, mapDom, isLocal, lonlat, scenes, laserRoot, laserOS
                                     if(time==key.time)return
                                     key.time = time
                                     AnimationEditor.reOrderKey(model, 'clip', key)
-                                    update()
+                                    updateAction()
                                 },
                                 changeDuration(dur){ 
                                     key.dur = dur
                                     AnimationEditor.updateTimeRange()
-                                    update()
+                                    updateAction()
                                 },
                                 changeAmplitude(weight){//修改动作幅度
                                     key.weight = weight
-                                    update()
+                                    updateAction()
                                 },
                                 changeSpeed(speed){
                                     key.speed = speed
-                                    update()
+                                    updateAction()
+                                },
+                                chose(state){ 
+                                    key.chosed = state  
+                                    updateAction() //选中后单独播放动作 
                                 }
+                                
                             } 
                         },