|
@@ -0,0 +1,995 @@
|
|
|
+// Potree.prototype.addEventListener = function(type, listener, importance=0){
|
|
|
+
|
|
|
+// }
|
|
|
+import * as THREE from "../../libs/three.js/build/three.module.js";
|
|
|
+import math from "../utils/math.js";
|
|
|
+import {Utils} from "../utils.js";
|
|
|
+import {BinaryLoader} from "../loader/BinaryLoader.js";
|
|
|
+// import {Features} from "../Features.js";
|
|
|
+import {PointAttribute,PointAttributeTypes} from "../loader/PointAttributes.js";
|
|
|
+import {ProfileWindow} from "../viewer/profile.js";
|
|
|
+import {XHRFactory} from "../XHRFactory.js";
|
|
|
+import {ClipTask, ClipMethod} from "../defines.js";
|
|
|
+import {Box3Helper} from "../utils/Box3Helper.js";
|
|
|
+import {KeyCodes} from "../KeyCodes.js";
|
|
|
+
|
|
|
+Utils.loadSkybox = function(path) {
|
|
|
+ let parent = new THREE.Object3D("skybox_root");
|
|
|
+
|
|
|
+ let camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 1, 100000);
|
|
|
+ if(!window.axisYup) camera.up.set(0, 0, 1);
|
|
|
+ let scene = new THREE.Scene();
|
|
|
+
|
|
|
+ let format = '.jpg';
|
|
|
+ let urls = [
|
|
|
+ path + 'px' + format, path + 'nx' + format,
|
|
|
+ path + 'py' + format, path + 'ny' + format,
|
|
|
+ path + 'pz' + format, path + 'nz' + format
|
|
|
+ ];
|
|
|
+
|
|
|
+ let materialArray = [];
|
|
|
+ {
|
|
|
+ for (let i = 0; i < 6; i++) {
|
|
|
+ let material = new THREE.MeshBasicMaterial({
|
|
|
+ map: null,
|
|
|
+ side: THREE.BackSide,
|
|
|
+ depthTest: false,
|
|
|
+ depthWrite: false,
|
|
|
+ color: 0x424556
|
|
|
+ });
|
|
|
+
|
|
|
+ materialArray.push(material);
|
|
|
+
|
|
|
+ let loader = new THREE.TextureLoader();
|
|
|
+ loader.load(urls[i],
|
|
|
+ function loaded (texture) {
|
|
|
+ material.map = texture;
|
|
|
+ material.needsUpdate = true;
|
|
|
+ material.color.setHex(0xffffff);
|
|
|
+ }, function progress (xhr) {
|
|
|
+ // console.log( (xhr.loaded / xhr.total * 100) + '% loaded' );
|
|
|
+ }, function error (xhr) {
|
|
|
+ console.log('An error happened', xhr);
|
|
|
+ }
|
|
|
+ );
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ let skyGeometry = new THREE.CubeGeometry(700, 700, 700);
|
|
|
+ let skybox = new THREE.Mesh(skyGeometry, materialArray);
|
|
|
+
|
|
|
+ scene.add(skybox);
|
|
|
+
|
|
|
+ scene.traverse(n => n.frustumCulled = false);
|
|
|
+
|
|
|
+ // z up
|
|
|
+ scene.rotation.x = Math.PI / 2;
|
|
|
+
|
|
|
+ parent.children.push(camera);
|
|
|
+ camera.parent = parent;
|
|
|
+
|
|
|
+ return {camera, scene, parent};
|
|
|
+};
|
|
|
+
|
|
|
+Utils.getMousePointCloudIntersection = function(viewport, mouse, pointer, camera, viewer, pointclouds, pickParams = {} ) {
|
|
|
+ if(!pointclouds || pointclouds.length == 0)return
|
|
|
+
|
|
|
+ let renderer = viewer.renderer;
|
|
|
+
|
|
|
+
|
|
|
+ if(viewport){ //转换到类似整个画面时
|
|
|
+
|
|
|
+ /*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;
|
|
|
+ }
|
|
|
+
|
|
|
+ //console.log('getMousePointCloudIntersection')
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ /* if(!raycaster){
|
|
|
+ raycaster = new THREE.Raycaster();
|
|
|
+ raycaster.setFromCamera(pointer, camera);
|
|
|
+ } */
|
|
|
+
|
|
|
+ let raycaster = new THREE.Raycaster();
|
|
|
+ raycaster.setFromCamera(pointer, camera);
|
|
|
+ let ray = raycaster.ray;
|
|
|
+
|
|
|
+ let selectedPointcloud = null;
|
|
|
+ let closestDistance = Infinity;
|
|
|
+ let closestIntersection = null;
|
|
|
+ let closestPoint = null;
|
|
|
+
|
|
|
+
|
|
|
+ let density
|
|
|
+ let sizeType
|
|
|
+ let size = new Map()
|
|
|
+ if(pickParams.isMeasuring || Potree.settings.displayMode == 'showPanos'){ //测量或全景模式提高精准度
|
|
|
+ density = Potree.settings.pointDensity
|
|
|
+ Potree.settings.pointDensity = 'magnifier'
|
|
|
+
|
|
|
+ pointclouds.forEach(e=>{//因为全景模式的pointSizeType是fixed所以要还原下
|
|
|
+ size.set(e, e.temp.pointSize)
|
|
|
+ sizeType = e.material.pointSizeType
|
|
|
+ e.material.pointSizeType = Potree.config.material.pointSizeType
|
|
|
+
|
|
|
+ e.changePointSize(Potree.config.material.realPointSize*2, true)//更改点云大小到能铺满为止,否则容易识别不到
|
|
|
+ })
|
|
|
+ Potree.updatePointClouds(pointclouds, camera, viewport.resolution );
|
|
|
+ }else{
|
|
|
+ if(viewer.viewports.filter(e=>!e.noPointcloud && e.active).length>1 || pickParams.cameraChanged){
|
|
|
+ viewport.beforeRender && viewport.beforeRender()
|
|
|
+ Potree.updatePointClouds(pointclouds, camera, viewport.resolution ); //不加这句的话hover久了会不准 因node是错的
|
|
|
+ //但依旧需要camera真的移动到那个位置才能加载出点云
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ let allPointclouds = []
|
|
|
+ for(let pointcloud of pointclouds){
|
|
|
+
|
|
|
+ let point = pointcloud.pick(viewer, viewport, camera, ray, pickParams );
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ if(!point){
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ allPointclouds.push(pointcloud)
|
|
|
+
|
|
|
+
|
|
|
+ let distance = camera.position.distanceTo(point.position);
|
|
|
+
|
|
|
+ if (distance < closestDistance) {
|
|
|
+ closestDistance = distance;
|
|
|
+ selectedPointcloud = pointcloud;
|
|
|
+ closestIntersection = point.position;
|
|
|
+ closestPoint = point;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ if(pickParams.isMeasuring || Potree.settings.displayMode == 'showPanos'){
|
|
|
+ Potree.settings.pointDensity = density
|
|
|
+
|
|
|
+ pointclouds.forEach(e=>{
|
|
|
+ e.material.pointSizeType = sizeType
|
|
|
+ e.changePointSize(size.get(e))
|
|
|
+
|
|
|
+ })
|
|
|
+ }else{
|
|
|
+ /* if(viewer.viewports.filter(e=>!e.noPointcloud).length>1){
|
|
|
+ viewport.afterRender && viewport.afterRender()
|
|
|
+ } */
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ if (selectedPointcloud) {
|
|
|
+ return {
|
|
|
+ location: closestIntersection,
|
|
|
+ distance: closestDistance,
|
|
|
+ pointcloud: selectedPointcloud,
|
|
|
+ point: closestPoint,
|
|
|
+ pointclouds: allPointclouds, //add
|
|
|
+ normal: new THREE.Vector3().fromArray(closestPoint.normal )//add
|
|
|
+ };
|
|
|
+ } else {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+};
|
|
|
+
|
|
|
+Utils.renderTargetToDataUrl = function(renderTarget, width, height, renderer, compressRatio = 0.7){
|
|
|
+ let pixelCount = width * height;
|
|
|
+ let buffer = new Uint8Array(4 * pixelCount);
|
|
|
+
|
|
|
+ renderer.readRenderTargetPixels(renderTarget, 0, 0, width, height, buffer);
|
|
|
+ var dataUrl = Utils.pixelsArrayToDataUrl(buffer, width, height, compressRatio)
|
|
|
+ return dataUrl
|
|
|
+
|
|
|
+}
|
|
|
+
|
|
|
+Utils.mouseToRay = function(pointer, camera ){
|
|
|
+
|
|
|
+ let vector = new THREE.Vector3(pointer.x, pointer.y, 1);
|
|
|
+ let origin = new THREE.Vector3(pointer.x, pointer.y, -1); //不能用camera.position,在orbitCamera时不准
|
|
|
+ vector.unproject(camera);
|
|
|
+ origin.unproject(camera);
|
|
|
+ let direction = new THREE.Vector3().subVectors(vector, origin).normalize();
|
|
|
+
|
|
|
+ let ray = new THREE.Ray(origin, direction);
|
|
|
+
|
|
|
+ return ray;
|
|
|
+}
|
|
|
+
|
|
|
+Utils.getPos2d = function(point, camera, dom, viewport){//获取一个三维坐标对应屏幕中的二维坐标
|
|
|
+ var pos
|
|
|
+ if(math.closeTo(camera.position, point, 1e-5) ){ //和相机位置重合时显示会四处飘,看是要改成一直显示中间还是隐藏?
|
|
|
+ pos = new THREE.Vector3(0,0,1.5); //1.5是为了不可见
|
|
|
+ }else{
|
|
|
+ pos = point.clone().project(camera) //比之前hotspot的计算方式写得简单 project用于3转2(求法同shader); unproject用于2转3 :new r.Vector3(e.x, e.y, -1).unproject(this.camera);
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ var x,y,left,top;
|
|
|
+ x = (pos.x + 1) / 2 * dom.clientWidth * viewport.width;
|
|
|
+ y = (1 - (pos.y + 1) / 2) * dom.clientHeight * viewport.height;
|
|
|
+ left = viewport.left * dom.clientWidth;
|
|
|
+ top = (1- viewport.bottom - viewport.height) * dom.clientHeight;
|
|
|
+
|
|
|
+
|
|
|
+ var inSight = pos.x <= 1 && pos.x >= -1 //是否在屏幕中
|
|
|
+ && pos.x <= 1 && pos.y >= -1
|
|
|
+
|
|
|
+
|
|
|
+ return {
|
|
|
+ pos: new THREE.Vector2(left+x,top+y) ,// 屏幕像素坐标
|
|
|
+ vector: pos, //(范围 -1 ~ 1)
|
|
|
+ trueSide : pos.z<1, //trueSide为false时,即使在屏幕范围内可见,也是反方向的另一个不可以被渲染的点 参见Tag.update
|
|
|
+ inSight : inSight, //在屏幕范围内可见,
|
|
|
+ posInViewport: new THREE.Vector2(x,y)
|
|
|
+ };
|
|
|
+}
|
|
|
+
|
|
|
+Utils.screenPass = new function () {
|
|
|
+ this.screenScene = new THREE.Scene();
|
|
|
+ this.screenQuad = new THREE.Mesh(new THREE.PlaneBufferGeometry(2, 2, 1));
|
|
|
+ this.screenQuad.material.depthTest = true;
|
|
|
+ this.screenQuad.material.depthWrite = true;
|
|
|
+ this.screenQuad.material.transparent = true;
|
|
|
+ this.screenScene.add(this.screenQuad);
|
|
|
+ this.camera = new THREE.Camera();
|
|
|
+
|
|
|
+ this.render = function (renderer, material, target) {
|
|
|
+ this.screenQuad.material = material;
|
|
|
+
|
|
|
+ if (typeof target === 'undefined') {
|
|
|
+ renderer.render(this.screenScene, this.camera);
|
|
|
+ } else {
|
|
|
+ renderer.setRenderTarget(target)
|
|
|
+ renderer.render(this.screenScene, this.camera);
|
|
|
+ }
|
|
|
+ };
|
|
|
+}();
|
|
|
+
|
|
|
+//add
|
|
|
+Utils.computePointcloudsBound = function(pointclouds){
|
|
|
+ var boundingBox = new THREE.Box3();
|
|
|
+ pointclouds.forEach(pointcloud=>{
|
|
|
+ pointcloud.updateBound()
|
|
|
+ boundingBox.union(pointcloud.bound)
|
|
|
+ })
|
|
|
+ var boundSize = boundingBox.getSize(new THREE.Vector3)
|
|
|
+ var center = boundingBox.getCenter(new THREE.Vector3)
|
|
|
+ return {boundSize, center, boundingBox}
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+Utils.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
|
|
|
+}
|
|
|
+
|
|
|
+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 的三维距离
|
|
|
+
|
|
|
+ let cameraViewWidth = camera.right / camera.zoom
|
|
|
+ let cameraViewHeight = camera.top / camera.zoom
|
|
|
+ let moveVec = new THREE.Vector3;
|
|
|
+ moveVec.set( pointerDelta.x * cameraViewWidth , pointerDelta.y * cameraViewHeight , 0).applyQuaternion(camera.quaternion)
|
|
|
+ return moveVec
|
|
|
+}
|
|
|
+
|
|
|
+Utils.VectorFactory = {
|
|
|
+ fromArray : function(t) {
|
|
|
+ if (t) {
|
|
|
+ if (t.length < 2 || t.length > 3)
|
|
|
+ console.error("Wrong number of ordinates for a point!");
|
|
|
+ return 3 === t.length ? (new THREE.Vector3).fromArray(t) : (new THREE.Vector2).fromArray(t)
|
|
|
+ }
|
|
|
+ },
|
|
|
+ fromArray3 : function(t) {
|
|
|
+ if (t) {
|
|
|
+ if (3 !== t.length)
|
|
|
+ console.error("Wrong number of ordinates for a point!");
|
|
|
+ return (new THREE.Vector3).fromArray(t)
|
|
|
+ }
|
|
|
+ },
|
|
|
+ fromArray2 : function(t) {
|
|
|
+ if (t) {
|
|
|
+ if (2 !== t.length)
|
|
|
+ console.error("Wrong number of ordinates for a point!");
|
|
|
+ return (new THREE.Vector2).fromArray(t)
|
|
|
+ }
|
|
|
+ },
|
|
|
+ toString : function(t) {
|
|
|
+ return t.x.toFixed(8) + "," + t.y.toFixed(8) + "," + t.z.toFixed(3)
|
|
|
+ }
|
|
|
+
|
|
|
+}
|
|
|
+
|
|
|
+Utils.QuaternionFactory = {
|
|
|
+ rot90 : (new THREE.Quaternion).setFromAxisAngle(new THREE.Vector3(0,0,1), THREE.Math.degToRad(-90)),
|
|
|
+ fromArray : function(t) {
|
|
|
+ if (t) {
|
|
|
+ if (4 !== t.length)
|
|
|
+ console.error("Wrong number of ordinates for a quaternion!");
|
|
|
+ return new THREE.Quaternion(t[1],t[2],t[3],t[0]).multiply(this.rot90)
|
|
|
+ }
|
|
|
+ }
|
|
|
+ ,
|
|
|
+ toArray : function(t) {
|
|
|
+ if (t) {
|
|
|
+ var e = t.clone().multiply(a).toArray();
|
|
|
+ return [e[3], e[0], e[1], e[2]]
|
|
|
+ }
|
|
|
+ }
|
|
|
+ ,
|
|
|
+ fromLonLat : function(t) {
|
|
|
+ if (t)
|
|
|
+ return (new THREE.Quaternion).setFromEuler(new THREE.Euler(t.lon,t.lat,0))
|
|
|
+ }
|
|
|
+ ,
|
|
|
+ toLonLat : function(t) {
|
|
|
+ if (t) {
|
|
|
+ var e = (new THREE.Euler).setFromQuaternion(t);
|
|
|
+ return {
|
|
|
+ lon: e.x,
|
|
|
+ lat: e.y
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+}
|
|
|
+
|
|
|
+Utils.datasetPosTransform = function(o={}){
|
|
|
+
|
|
|
+ let pointcloud = o.pointcloud || viewer.scene.pointclouds.find(e=>e.dataset_id == o.datasetId)
|
|
|
+ let tranMatrix
|
|
|
+ if(pointcloud){
|
|
|
+ if(Potree.settings.editType == 'merge'){
|
|
|
+ tranMatrix = o.fromDataset ? pointcloud.matrixWorld : new THREE.Matrix4().copy(pointcloud.matrixWorld).invert()
|
|
|
+ }else{
|
|
|
+ tranMatrix = o.fromDataset ? pointcloud.transformMatrix : pointcloud.transformInvMatrix
|
|
|
+ }
|
|
|
+ }else{
|
|
|
+ if(Potree.settings.intersectOnObjs){
|
|
|
+ let object = o.object || viewer.objs.children.find(e=>e.dataset_id == o.datasetId)
|
|
|
+ if(object){
|
|
|
+ tranMatrix = o.fromDataset ? object.matrixWorld : new THREE.Matrix4().copy(object.matrixWorld).invert()
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if(tranMatrix){
|
|
|
+ return (new THREE.Vector3).copy(o.position).applyMatrix4(tranMatrix)
|
|
|
+ }else{
|
|
|
+ if(o.datasetId != void 0){
|
|
|
+ console.error(`datasetPosTransform找不到datasetId为${o.datasetId}的数据集或模型,请检查数据, 模型未创建或删除`)
|
|
|
+ //很可能是旧的热点,需要删除
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+}
|
|
|
+
|
|
|
+Utils.datasetRotTransform = function(o={}){
|
|
|
+ let pointcloud = o.pointcloud || viewer.scene.pointclouds.find(e=>e.dataset_id == o.datasetId)
|
|
|
+ if(pointcloud){
|
|
|
+ var matrix, newMatrix, result
|
|
|
+
|
|
|
+ if(o.rotation){
|
|
|
+ matrix = new THREE.Matrix4().makeRotationFromEuler(o.rotation)
|
|
|
+ }else if(o.quaternion){
|
|
|
+ matrix = new THREE.Matrix4().makeRotationFromQuaternion(o.quaternion)
|
|
|
+ }else if(o.matrix){
|
|
|
+ matrix = o.matrix.clone()
|
|
|
+ }else{
|
|
|
+ return
|
|
|
+ }
|
|
|
+ let rotateMatrix = o.fromDataset ? pointcloud.rotateMatrix : pointcloud.rotateInvMatrix
|
|
|
+ newMatrix = new THREE.Matrix4().multiplyMatrices(rotateMatrix, matrix )
|
|
|
+
|
|
|
+ if(o.getRotation){
|
|
|
+ result = new THREE.Euler().setFromRotationMatrix(newMatrix)
|
|
|
+ }else if(o.getQuaternion){
|
|
|
+ result = new THREE.Quaternion().setFromRotationMatrix(newMatrix)
|
|
|
+ }else if(o.getMatrix){
|
|
|
+ result = newMatrix
|
|
|
+ }
|
|
|
+
|
|
|
+ return result
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+}
|
|
|
+
|
|
|
+Utils.isInsideFrustum = function(bounding, camera){// boundingBox在视野范围内有可见部分
|
|
|
+ let frustumMatrix = new THREE.Matrix4
|
|
|
+ frustumMatrix.multiplyMatrices(camera.projectionMatrix, camera.matrixWorldInverse)
|
|
|
+
|
|
|
+ let frustum = new THREE.Frustum();
|
|
|
+ frustum.setFromProjectionMatrix(frustumMatrix)
|
|
|
+
|
|
|
+ if(bounding instanceof THREE.Sphere){
|
|
|
+ return frustum.intersectsSphere(bounding)
|
|
|
+ }else{
|
|
|
+ return frustum.intersectsBox(bounding)
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+Utils.isInsideBox = function(object, boxMatrixInverse){//object可以是点或者bounding, box原为1*1*1,但可能形变
|
|
|
+ let frustum = new THREE.Frustum();
|
|
|
+ frustum.setFromProjectionMatrix(boxMatrixInverse)
|
|
|
+
|
|
|
+ if(object instanceof THREE.Box3){
|
|
|
+ return frustum.intersectsSphere(object)
|
|
|
+ }else if(object instanceof Array){//点合集,先求Sphere setFromPoints
|
|
|
+ let sphere = new THREE.Sphere()
|
|
|
+ sphere.setFromPoints(object)
|
|
|
+ return this.isInsideBox(sphere, boxMatrixInverse)
|
|
|
+
|
|
|
+ }else if(object instanceof THREE.Sphere){
|
|
|
+ return frustum.intersectsSphere(object)
|
|
|
+ }else if(object instanceof THREE.Vector3){
|
|
|
+ return frustum.containsPoint(object)
|
|
|
+ }
|
|
|
+
|
|
|
+ /* containsPoint: ƒ containsPoint( point )
|
|
|
+ intersectsBox: ƒ intersectsBox( box )
|
|
|
+ intersectsObject: ƒ intersectsObject( object )//geo
|
|
|
+ intersectsSphere: ƒ intersectsSphere( sphere )
|
|
|
+ intersectsSprite: ƒ intersectsSprite( sprite )
|
|
|
+ */
|
|
|
+
|
|
|
+}
|
|
|
+
|
|
|
+Utils.getIntersect = function (camera, meshes, pointer, raycaster) {
|
|
|
+ //获取鼠标和meshes交点
|
|
|
+ camera.updateMatrixWorld()
|
|
|
+ if(!raycaster){//getMouseIntersect
|
|
|
+ raycaster = new THREE.Raycaster()
|
|
|
+ var origin = new THREE.Vector3(pointer.x, pointer.y, -1).unproject(camera),
|
|
|
+ end = new THREE.Vector3(pointer.x, pointer.y, 1).unproject(camera)
|
|
|
+ var dir = end.sub(origin).normalize()
|
|
|
+ raycaster.set(origin, dir)
|
|
|
+ }
|
|
|
+
|
|
|
+ meshes.forEach(e=>{
|
|
|
+ raycaster.layers.enable(math.getBaseLog(e.layers.mask,2))
|
|
|
+ })
|
|
|
+ var n = raycaster.intersectObjects(meshes)
|
|
|
+ if (0 === n.length) return null
|
|
|
+ return n[0]
|
|
|
+}
|
|
|
+
|
|
|
+BinaryLoader.prototype.load = function(node){
|
|
|
+ if (node.loaded) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ let url = node.getURL();
|
|
|
+
|
|
|
+ if (this.version.equalOrHigher('1.4')) {
|
|
|
+ url += '.bin';
|
|
|
+ }
|
|
|
+ url += '?m='+node.pcoGeometry.timeStamp //add
|
|
|
+
|
|
|
+ let xhr = XHRFactory.createXMLHttpRequest();
|
|
|
+ xhr.open('GET', url, true);
|
|
|
+ xhr.responseType = 'arraybuffer';
|
|
|
+ xhr.overrideMimeType('text/plain; charset=x-user-defined');
|
|
|
+ xhr.onreadystatechange = () => {
|
|
|
+ if (xhr.readyState === 4) {
|
|
|
+ if((xhr.status === 200 || xhr.status === 0) && xhr.response !== null){
|
|
|
+ let buffer = xhr.response;
|
|
|
+ this.parse(node, buffer);
|
|
|
+ } else {
|
|
|
+ //console.error(`Failed to load file! HTTP status: ${xhr.status}, file: ${url}`);
|
|
|
+ throw new Error(`Failed to load file! HTTP status: ${xhr.status}, file: ${url}`);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
+ try {
|
|
|
+ xhr.send(null);
|
|
|
+ } catch (e) {
|
|
|
+ console.log('fehler beim laden der punktwolke: ' + e);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+PointAttribute.RGBA_PACKED = new PointAttribute("rgba", PointAttributeTypes.DATA_TYPE_INT8, 4);
|
|
|
+
|
|
|
+PointAttribute.INTENSITY = new PointAttribute("intensity", PointAttributeTypes.DATA_TYPE_UINT16, 1);
|
|
|
+
|
|
|
+PointAttribute.CLASSIFICATION = new PointAttribute("classification", PointAttributeTypes.DATA_TYPE_UINT8, 1);
|
|
|
+
|
|
|
+PointAttribute.GPS_TIME = new PointAttribute("gps-time", PointAttributeTypes.DATA_TYPE_DOUBLE, 1);
|
|
|
+
|
|
|
+ProfileWindow.prototype.initTHREE = function(){
|
|
|
+ this.renderer = new THREE.WebGLRenderer({alpha: true, premultipliedAlpha: false});
|
|
|
+ this.renderer.setClearColor(0x000000, 0);
|
|
|
+ this.renderer.setSize(10, 10);
|
|
|
+ this.renderer.autoClear = false;
|
|
|
+ this.renderArea.append($(this.renderer.domElement));
|
|
|
+ this.renderer.domElement.tabIndex = '2222';
|
|
|
+ $(this.renderer.domElement).css('width', '100%');
|
|
|
+ $(this.renderer.domElement).css('height', '100%');
|
|
|
+
|
|
|
+
|
|
|
+ {
|
|
|
+ let gl = this.renderer.getContext();
|
|
|
+
|
|
|
+ if(gl.createVertexArray == null){
|
|
|
+ let extVAO = gl.getExtension('OES_vertex_array_object');
|
|
|
+
|
|
|
+ if(!extVAO){
|
|
|
+ throw new Error("OES_vertex_array_object extension not supported");
|
|
|
+ }
|
|
|
+
|
|
|
+ gl.createVertexArray = extVAO.createVertexArrayOES.bind(extVAO);
|
|
|
+ gl.bindVertexArray = extVAO.bindVertexArrayOES.bind(extVAO);
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ this.camera = new THREE.OrthographicCamera(-1000, 1000, 1000, -1000, -1000, 1000);
|
|
|
+ this.camera.up.set(0, 0, 1);
|
|
|
+ this.camera.rotation.order = "ZXY";
|
|
|
+ this.camera.rotation.x = Math.PI / 2.0;
|
|
|
+
|
|
|
+
|
|
|
+ this.scene = new THREE.Scene();
|
|
|
+ this.profileScene = new THREE.Scene();
|
|
|
+
|
|
|
+ let sg = new THREE.SphereGeometry(1, 16, 16);
|
|
|
+ let sm = new THREE.MeshNormalMaterial();
|
|
|
+ this.pickSphere = new THREE.Mesh(sg, sm);
|
|
|
+ this.scene.add(this.pickSphere);
|
|
|
+
|
|
|
+ this.viewerPickSphere = new THREE.Mesh(sg, sm);
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+Potree.updatePointClouds = function(pointclouds,camera, areaSize /* renderer */){
|
|
|
+
|
|
|
+ for (let pointcloud of pointclouds) {
|
|
|
+ let start = performance.now();
|
|
|
+
|
|
|
+ for (let profileRequest of pointcloud.profileRequests) {
|
|
|
+ profileRequest.update();
|
|
|
+
|
|
|
+ let duration = performance.now() - start;
|
|
|
+ if(duration > 5){
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ let duration = performance.now() - start;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ let result = Potree.updateVisibility(pointclouds, camera, areaSize );
|
|
|
+
|
|
|
+ for (let pointcloud of pointclouds) {
|
|
|
+ //pointcloud.updateMaterial(pointcloud.material, pointcloud.visibleNodes, camera, renderer);//转移到渲染时
|
|
|
+ pointcloud.updateVisibleBounds();
|
|
|
+ }
|
|
|
+
|
|
|
+ exports.lru.freeMemory();//即Potree.lru 能看到所有在加载的node
|
|
|
+
|
|
|
+ return result;
|
|
|
+};
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+Potree.updateVisibilityStructures = function(pointclouds, camera, areaSize) {
|
|
|
+ let frustums = [];
|
|
|
+ let camObjPositions = [];
|
|
|
+ let priorityQueue = new BinaryHeap(function (x) { return 1 / x.weight; });
|
|
|
+
|
|
|
+ for (let i = 0; i < pointclouds.length; i++) {
|
|
|
+ let pointcloud = pointclouds[i];
|
|
|
+
|
|
|
+ if (!pointcloud.initialized()) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+ pointcloud.numVisibleNodes = 0;
|
|
|
+ pointcloud.numVisiblePoints = 0;
|
|
|
+ pointcloud.deepestVisibleLevel = 0;
|
|
|
+ pointcloud.visibleNodes = [];
|
|
|
+ pointcloud.visibleGeometry = [];
|
|
|
+
|
|
|
+ // frustum in object space
|
|
|
+ camera.updateMatrixWorld();
|
|
|
+ let frustum = new THREE.Frustum();
|
|
|
+ let viewI = camera.matrixWorldInverse;
|
|
|
+ let world = pointcloud.matrixWorld;
|
|
|
+
|
|
|
+ // use close near plane for frustum intersection
|
|
|
+ let frustumCam = camera.clone();
|
|
|
+ frustumCam.near = Math.min(camera.near, 0.1);
|
|
|
+ frustumCam.updateProjectionMatrix();
|
|
|
+ let proj = camera.projectionMatrix;
|
|
|
+
|
|
|
+ let fm = new THREE.Matrix4().multiply(proj).multiply(viewI).multiply(world);
|
|
|
+ frustum.setFromProjectionMatrix(fm);
|
|
|
+ frustums.push(frustum);
|
|
|
+
|
|
|
+ // camera position in object space
|
|
|
+ let view = camera.matrixWorld;
|
|
|
+ let worldI = world.clone().invert();
|
|
|
+ let camMatrixObject = new THREE.Matrix4().multiply(worldI).multiply(view);
|
|
|
+ let camObjPos = new THREE.Vector3().setFromMatrixPosition(camMatrixObject);
|
|
|
+ camObjPositions.push(camObjPos);
|
|
|
+
|
|
|
+ // 因漫游模式而隐藏的话 依旧需要加入visibleNodes,因为pick需要
|
|
|
+
|
|
|
+ /* viewer.getObjVisiByReason(pointcloud, 'datasetSelection') */
|
|
|
+ if (pointcloud.visible || pointcloud.unvisibleReasons && pointcloud.unvisibleReasons.length == 1 && pointcloud.unvisibleReasons[0].reason == 'displayMode' && pointcloud.root !== null) {//改 visible ->
|
|
|
+ priorityQueue.push({pointcloud: i, node: pointcloud.root, weight: Number.MAX_VALUE});
|
|
|
+ }
|
|
|
+
|
|
|
+ // hide all previously visible nodes
|
|
|
+ // if(pointcloud.root instanceof PointCloudOctreeNode){
|
|
|
+ // pointcloud.hideDescendants(pointcloud.root.sceneNode);
|
|
|
+ // }
|
|
|
+ if (pointcloud.root.isTreeNode()) {
|
|
|
+ pointcloud.hideDescendants(pointcloud.root.sceneNode);
|
|
|
+ }
|
|
|
+
|
|
|
+ for (let j = 0; j < pointcloud.boundingBoxNodes.length; j++) {
|
|
|
+ pointcloud.boundingBoxNodes[j].visible = false;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return {
|
|
|
+ 'frustums': frustums,
|
|
|
+ 'camObjPositions': camObjPositions,
|
|
|
+ 'priorityQueue': priorityQueue
|
|
|
+ };
|
|
|
+};
|
|
|
+
|
|
|
+
|
|
|
+Potree.updateVisibility = function(pointclouds, camera, areaSize){
|
|
|
+
|
|
|
+ let numVisibleNodes = 0;
|
|
|
+ let numVisiblePoints = 0;
|
|
|
+
|
|
|
+ let numVisiblePointsInPointclouds = new Map(pointclouds.map(pc => [pc, 0]));
|
|
|
+
|
|
|
+ let visibleNodes = [];
|
|
|
+ let visibleGeometry = [];
|
|
|
+ let unloadedGeometry = [];
|
|
|
+
|
|
|
+ let lowestSpacing = Infinity;
|
|
|
+
|
|
|
+ // calculate object space frustum and cam pos and setup priority queue
|
|
|
+ let s = Potree.updateVisibilityStructures(pointclouds, camera, areaSize);//得到相机可见范围
|
|
|
+ let frustums = s.frustums;
|
|
|
+ let camObjPositions = s.camObjPositions;
|
|
|
+ let priorityQueue = s.priorityQueue;
|
|
|
+
|
|
|
+ let loadedToGPUThisFrame = 0;
|
|
|
+
|
|
|
+ let domWidth = areaSize.x; //renderer.domElement.clientWidth;
|
|
|
+ let domHeight = areaSize.y;//renderer.domElement.clientHeight;
|
|
|
+
|
|
|
+ // check if pointcloud has been transformed
|
|
|
+ // some code will only be executed if changes have been detected
|
|
|
+ if(!Potree._pointcloudTransformVersion){
|
|
|
+ Potree._pointcloudTransformVersion = new Map();
|
|
|
+ }
|
|
|
+ let pointcloudTransformVersion = Potree._pointcloudTransformVersion;
|
|
|
+ for(let pointcloud of pointclouds){
|
|
|
+
|
|
|
+ if(!viewer.getObjVisiByReason(pointcloud, 'datasetSelection')){//改 visible ->
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+ pointcloud.updateMatrixWorld();
|
|
|
+
|
|
|
+ if(!pointcloudTransformVersion.has(pointcloud)){
|
|
|
+ pointcloudTransformVersion.set(pointcloud, {number: 0, transform: pointcloud.matrixWorld.clone()});
|
|
|
+ }else{
|
|
|
+ let version = pointcloudTransformVersion.get(pointcloud);
|
|
|
+
|
|
|
+ if(!version.transform.equals(pointcloud.matrixWorld)){
|
|
|
+ version.number++;
|
|
|
+ version.transform.copy(pointcloud.matrixWorld);
|
|
|
+
|
|
|
+ pointcloud.dispatchEvent({
|
|
|
+ type: "transformation_changed",
|
|
|
+ target: pointcloud
|
|
|
+ });
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ while (priorityQueue.size() > 0) {
|
|
|
+ let element = priorityQueue.pop();//其实是拿第一个, 再把最后一个放到前面
|
|
|
+
|
|
|
+ let node = element.node;
|
|
|
+ let parent = element.parent;
|
|
|
+ let pointcloud = pointclouds[element.pointcloud];
|
|
|
+
|
|
|
+ // { // restrict to certain nodes for debugging
|
|
|
+ // let allowedNodes = ["r", "r0", "r4"];
|
|
|
+ // if(!allowedNodes.includes(node.name)){
|
|
|
+ // continue;
|
|
|
+ // }
|
|
|
+ // }
|
|
|
+
|
|
|
+ let box = node.getBoundingBox();
|
|
|
+ let frustum = frustums[element.pointcloud];
|
|
|
+ let camObjPos = camObjPositions[element.pointcloud];
|
|
|
+
|
|
|
+ let insideFrustum = frustum.intersectsBox(box);
|
|
|
+ let maxLevel = pointcloud.maxLevel == void 0 ? Infinity : pointcloud.maxLevel;
|
|
|
+ let level = node.getLevel();
|
|
|
+ let visible = insideFrustum;
|
|
|
+ visible = visible && !(numVisiblePoints + node.getNumPoints() > Potree.pointBudget);
|
|
|
+ visible = visible && !(numVisiblePointsInPointclouds.get(pointcloud) + node.getNumPoints() > pointcloud.pointBudget);
|
|
|
+ visible = visible && level <= maxLevel; //< 改为 <=
|
|
|
+ //visible = visible || node.getLevel() <= 2;
|
|
|
+
|
|
|
+ let clipBoxes = pointcloud.material.clipBoxes;
|
|
|
+ if(true && clipBoxes.length > 0){
|
|
|
+
|
|
|
+ //node.debug = false;
|
|
|
+
|
|
|
+ let numIntersecting = 0;
|
|
|
+ let numIntersectionVolumes = 0;
|
|
|
+
|
|
|
+ //if(node.name === "r60"){
|
|
|
+ // var a = 10;
|
|
|
+ //}
|
|
|
+
|
|
|
+ for(let clipBox of clipBoxes){
|
|
|
+
|
|
|
+ let pcWorldInverse = pointcloud.matrixWorld.clone().invert();
|
|
|
+ let toPCObject = pcWorldInverse.multiply(clipBox.box.matrixWorld);
|
|
|
+
|
|
|
+ let px = new THREE.Vector3(+0.5, 0, 0).applyMatrix4(pcWorldInverse);
|
|
|
+ let nx = new THREE.Vector3(-0.5, 0, 0).applyMatrix4(pcWorldInverse);
|
|
|
+ let py = new THREE.Vector3(0, +0.5, 0).applyMatrix4(pcWorldInverse);
|
|
|
+ let ny = new THREE.Vector3(0, -0.5, 0).applyMatrix4(pcWorldInverse);
|
|
|
+ let pz = new THREE.Vector3(0, 0, +0.5).applyMatrix4(pcWorldInverse);
|
|
|
+ let nz = new THREE.Vector3(0, 0, -0.5).applyMatrix4(pcWorldInverse);
|
|
|
+
|
|
|
+ let pxN = new THREE.Vector3().subVectors(nx, px).normalize();
|
|
|
+ let nxN = pxN.clone().multiplyScalar(-1);
|
|
|
+ let pyN = new THREE.Vector3().subVectors(ny, py).normalize();
|
|
|
+ let nyN = pyN.clone().multiplyScalar(-1);
|
|
|
+ let pzN = new THREE.Vector3().subVectors(nz, pz).normalize();
|
|
|
+ let nzN = pzN.clone().multiplyScalar(-1);
|
|
|
+
|
|
|
+ let pxPlane = new THREE.Plane().setFromNormalAndCoplanarPoint(pxN, px);
|
|
|
+ let nxPlane = new THREE.Plane().setFromNormalAndCoplanarPoint(nxN, nx);
|
|
|
+ let pyPlane = new THREE.Plane().setFromNormalAndCoplanarPoint(pyN, py);
|
|
|
+ let nyPlane = new THREE.Plane().setFromNormalAndCoplanarPoint(nyN, ny);
|
|
|
+ let pzPlane = new THREE.Plane().setFromNormalAndCoplanarPoint(pzN, pz);
|
|
|
+ let nzPlane = new THREE.Plane().setFromNormalAndCoplanarPoint(nzN, nz);
|
|
|
+
|
|
|
+ //if(window.debugdraw !== undefined && window.debugdraw === true && node.name === "r60"){
|
|
|
+
|
|
|
+ // Potree.utils.debugPlane(viewer.scene.scene, pxPlane, 1, 0xFF0000);
|
|
|
+ // Potree.utils.debugPlane(viewer.scene.scene, nxPlane, 1, 0x990000);
|
|
|
+ // Potree.utils.debugPlane(viewer.scene.scene, pyPlane, 1, 0x00FF00);
|
|
|
+ // Potree.utils.debugPlane(viewer.scene.scene, nyPlane, 1, 0x009900);
|
|
|
+ // Potree.utils.debugPlane(viewer.scene.scene, pzPlane, 1, 0x0000FF);
|
|
|
+ // Potree.utils.debugPlane(viewer.scene.scene, nzPlane, 1, 0x000099);
|
|
|
+
|
|
|
+ // Potree.utils.debugBox(viewer.scene.scene, box, new THREE.Matrix4(), 0x00FF00);
|
|
|
+ // Potree.utils.debugBox(viewer.scene.scene, box, pointcloud.matrixWorld, 0xFF0000);
|
|
|
+ // Potree.utils.debugBox(viewer.scene.scene, clipBox.box.boundingBox, clipBox.box.matrixWorld, 0xFF0000);
|
|
|
+
|
|
|
+ // window.debugdraw = false;
|
|
|
+ //}
|
|
|
+
|
|
|
+ let frustum = new THREE.Frustum(pxPlane, nxPlane, pyPlane, nyPlane, pzPlane, nzPlane);
|
|
|
+ let intersects = frustum.intersectsBox(box);
|
|
|
+
|
|
|
+ if(intersects){
|
|
|
+ numIntersecting++;
|
|
|
+ }
|
|
|
+ numIntersectionVolumes++;
|
|
|
+ }
|
|
|
+
|
|
|
+ let insideAny = numIntersecting > 0;
|
|
|
+ let insideAll = numIntersecting === numIntersectionVolumes;
|
|
|
+
|
|
|
+ if(pointcloud.material.clipTask === ClipTask.SHOW_INSIDE){
|
|
|
+ if(pointcloud.material.clipMethod === ClipMethod.INSIDE_ANY && insideAny){
|
|
|
+ //node.debug = true
|
|
|
+ }else if(pointcloud.material.clipMethod === ClipMethod.INSIDE_ALL && insideAll){
|
|
|
+ //node.debug = true;
|
|
|
+ }else{
|
|
|
+ visible = false;
|
|
|
+ }
|
|
|
+ } else if(pointcloud.material.clipTask === ClipTask.SHOW_OUTSIDE){
|
|
|
+ //if(pointcloud.material.clipMethod === ClipMethod.INSIDE_ANY && !insideAny){
|
|
|
+ // //visible = true;
|
|
|
+ // let a = 10;
|
|
|
+ //}else if(pointcloud.material.clipMethod === ClipMethod.INSIDE_ALL && !insideAll){
|
|
|
+ // //visible = true;
|
|
|
+ // let a = 20;
|
|
|
+ //}else{
|
|
|
+ // visible = false;
|
|
|
+ //}
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ // visible = ["r", "r0", "r06", "r060"].includes(node.name);
|
|
|
+ // visible = ["r"].includes(node.name);
|
|
|
+
|
|
|
+ if (node.spacing) {
|
|
|
+ lowestSpacing = Math.min(lowestSpacing, node.spacing);
|
|
|
+ } else if (node.geometryNode && node.geometryNode.spacing) {
|
|
|
+ lowestSpacing = Math.min(lowestSpacing, node.geometryNode.spacing);
|
|
|
+ }
|
|
|
+
|
|
|
+ if (numVisiblePoints + node.getNumPoints() > Potree.pointBudget) {
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!visible) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+ // TODO: not used, same as the declaration?
|
|
|
+ // numVisibleNodes++;
|
|
|
+ numVisiblePoints += node.getNumPoints();
|
|
|
+ let numVisiblePointsInPointcloud = numVisiblePointsInPointclouds.get(pointcloud);
|
|
|
+ numVisiblePointsInPointclouds.set(pointcloud, numVisiblePointsInPointcloud + node.getNumPoints());
|
|
|
+
|
|
|
+ pointcloud.numVisibleNodes++;
|
|
|
+ pointcloud.numVisiblePoints += node.getNumPoints();
|
|
|
+
|
|
|
+ if (node.isGeometryNode() && (!parent || parent.isTreeNode())) {
|
|
|
+ if (node.isLoaded() && loadedToGPUThisFrame < 2) {
|
|
|
+ node = pointcloud.toTreeNode(node, parent);
|
|
|
+ loadedToGPUThisFrame++;
|
|
|
+ } else {
|
|
|
+ unloadedGeometry.push({pointcloud,node});
|
|
|
+ visibleGeometry.push(node);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (node.isTreeNode()) {
|
|
|
+ exports.lru.touch(node.geometryNode);
|
|
|
+ node.sceneNode.visible = true;
|
|
|
+ node.sceneNode.material = pointcloud.material;
|
|
|
+
|
|
|
+ visibleNodes.push(node);
|
|
|
+ pointcloud.visibleNodes.push(node);
|
|
|
+
|
|
|
+ if(node._transformVersion === undefined){
|
|
|
+ node._transformVersion = -1;
|
|
|
+ }
|
|
|
+ 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;
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ if (pointcloud.showBoundingBox && !node.boundingBoxNode && node.getBoundingBox) {
|
|
|
+ let boxHelper = new Box3Helper(node.getBoundingBox());
|
|
|
+ boxHelper.matrixAutoUpdate = false;
|
|
|
+ pointcloud.boundingBoxNodes.push(boxHelper);
|
|
|
+ node.boundingBoxNode = boxHelper;
|
|
|
+ node.boundingBoxNode.matrix.copy(pointcloud.matrixWorld);
|
|
|
+ } else if (pointcloud.showBoundingBox) {
|
|
|
+ node.boundingBoxNode.visible = true;
|
|
|
+ node.boundingBoxNode.matrix.copy(pointcloud.matrixWorld);
|
|
|
+ } else if (!pointcloud.showBoundingBox && node.boundingBoxNode) {
|
|
|
+ node.boundingBoxNode.visible = false;
|
|
|
+ }
|
|
|
+
|
|
|
+ // if(node.boundingBoxNode !== undefined && exports.debug.allowedNodes !== undefined){
|
|
|
+ // if(!exports.debug.allowedNodes.includes(node.name)){
|
|
|
+ // node.boundingBoxNode.visible = false;
|
|
|
+ // }
|
|
|
+ // }
|
|
|
+ }
|
|
|
+
|
|
|
+ // add child nodes to priorityQueue
|
|
|
+ let children = node.getChildren();
|
|
|
+ for (let i = 0; i < children.length; i++) {
|
|
|
+ let child = children[i];
|
|
|
+
|
|
|
+ let weight = 0;
|
|
|
+ if(camera.isPerspectiveCamera){
|
|
|
+ let sphere = child.getBoundingSphere();
|
|
|
+ let center = sphere.center;
|
|
|
+ //let distance = sphere.center.distanceTo(camObjPos);
|
|
|
+
|
|
|
+ let dx = camObjPos.x - center.x;
|
|
|
+ let dy = camObjPos.y - center.y;
|
|
|
+ let dz = camObjPos.z - center.z;
|
|
|
+
|
|
|
+ let dd = dx * dx + dy * dy + dz * dz;
|
|
|
+ let distance = Math.sqrt(dd);
|
|
|
+
|
|
|
+
|
|
|
+ let radius = sphere.radius;
|
|
|
+
|
|
|
+ let fov = (camera.fov * Math.PI) / 180;
|
|
|
+ let slope = Math.tan(fov / 2);
|
|
|
+ let projFactor = (0.5 * domHeight) / (slope * distance);
|
|
|
+ let screenPixelRadius = radius * projFactor;
|
|
|
+
|
|
|
+ if(screenPixelRadius < pointcloud.minimumNodePixelSize){
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+ weight = screenPixelRadius;
|
|
|
+
|
|
|
+ if(distance - radius < 0){
|
|
|
+ weight = Number.MAX_VALUE;
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ // TODO ortho visibility
|
|
|
+ let bb = child.getBoundingBox();
|
|
|
+ let distance = child.getBoundingSphere().center.distanceTo(camObjPos);
|
|
|
+ let diagonal = bb.max.clone().sub(bb.min).length();
|
|
|
+ //weight = diagonal / distance;
|
|
|
+
|
|
|
+ weight = diagonal;
|
|
|
+ }
|
|
|
+
|
|
|
+ priorityQueue.push({pointcloud: element.pointcloud, node: child, parent: node, weight: weight});
|
|
|
+ }
|
|
|
+ }// end priority queue loop
|
|
|
+
|
|
|
+ { // update DEM 这是什么
|
|
|
+ let maxDEMLevel = 4;
|
|
|
+ let candidates = pointclouds.filter(p => (p.generateDEM && p.dem instanceof Potree.DEM));
|
|
|
+ for (let pointcloud of candidates) {
|
|
|
+ let updatingNodes = pointcloud.visibleNodes.filter(n => n.getLevel() <= maxDEMLevel);
|
|
|
+ pointcloud.dem.update(updatingNodes);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ //加载点云
|
|
|
+ for (let i = 0; i < Math.min(Potree.maxNodesLoading, unloadedGeometry.length); i++) {
|
|
|
+ unloadedGeometry[i].node.load(unloadedGeometry[i].pointcloud.pcoGeometry);
|
|
|
+ }
|
|
|
+
|
|
|
+ return {
|
|
|
+ visibleNodes: visibleNodes,
|
|
|
+ numVisiblePoints: numVisiblePoints,
|
|
|
+ lowestSpacing: lowestSpacing
|
|
|
+ };
|
|
|
+};
|
|
|
+
|
|
|
+KeyCodes.BACKSPACE = 8
|