|
@@ -72,6 +72,7 @@ export class Viewer extends ViewerBase{
|
|
|
this.isEdit = true
|
|
|
CursorDeal.attachToViewer(this)//ADD
|
|
|
this.unitConvert = new UoMService();
|
|
|
+
|
|
|
//-------------
|
|
|
|
|
|
|
|
@@ -163,7 +164,25 @@ export class Viewer extends ViewerBase{
|
|
|
|
|
|
}
|
|
|
|
|
|
-
|
|
|
+ if(!Potree.settings.isOfficial){
|
|
|
+ let domRoot = this.renderer.domElement.parentElement;
|
|
|
+ let elAttach = $("<input type='button' value='test'></input>");
|
|
|
+ elAttach.css({
|
|
|
+ position : "absolute",
|
|
|
+ right : '10%',
|
|
|
+ bottom: '20px',
|
|
|
+ zIndex: "10000",
|
|
|
+ fontSize:'1em', color:"black",
|
|
|
+ background:'rgba(255,255,255,0.8)',
|
|
|
+ })
|
|
|
+ let state = false
|
|
|
+ elAttach.on("click", () => {
|
|
|
+ window.buttonFunction && window.buttonFunction()
|
|
|
+ });
|
|
|
+ domRoot.appendChild(elAttach[0]);
|
|
|
+
|
|
|
+
|
|
|
+ }
|
|
|
|
|
|
}
|
|
|
|
|
@@ -319,7 +338,7 @@ export class Viewer extends ViewerBase{
|
|
|
this.reticule = new Reticule(this)
|
|
|
this.scene.scene.add(this.magnifier)
|
|
|
this.scene.scene.add(this.reticule)
|
|
|
- this.mainViewport = new Viewport(this.renderer, this.scene.view, this.scene.cameraP, {
|
|
|
+ this.mainViewport = new Viewport( this.scene.view, this.scene.cameraP, {
|
|
|
left:0, bottom:0, width:1, height: 1, name:'MainView'
|
|
|
})
|
|
|
this.viewports = [this.mainViewport]
|
|
@@ -1864,10 +1883,7 @@ export class Viewer extends ViewerBase{
|
|
|
this.viewports.forEach(viewport=>{
|
|
|
if(!viewport.active)return
|
|
|
viewport.view.applyToCamera(viewport.camera)
|
|
|
- viewport.camera.updateMatrix();
|
|
|
- viewport.camera.updateMatrixWorld();
|
|
|
- viewport.camera.matrixWorldInverse.copy(viewport.camera.matrixWorld).invert();
|
|
|
-
|
|
|
+
|
|
|
})
|
|
|
}
|
|
|
|
|
@@ -2228,12 +2244,18 @@ export class Viewer extends ViewerBase{
|
|
|
|
|
|
renderDefault(params_={}){
|
|
|
let pRenderer = this.getPRenderer();
|
|
|
-
|
|
|
+ let renderSize
|
|
|
+ if(params_.target){
|
|
|
+ renderSize = new THREE.Vector2(params_.target.width, params_.target.height)
|
|
|
+ }else{
|
|
|
+ renderSize = this.renderer.getSize(new THREE.Vector2());
|
|
|
+ }
|
|
|
+
|
|
|
|
|
|
- let renderSize = this.renderer.getSize(new THREE.Vector2());
|
|
|
- let needSResize = this.viewports.length > 1 || params_.resize
|
|
|
var viewports = params_.viewports || this.viewports
|
|
|
-
|
|
|
+ let needSResize = viewports.length > 1 || params_.resize
|
|
|
+
|
|
|
+
|
|
|
|
|
|
viewports.forEach(view=>{
|
|
|
let params = $.extend({},params_);
|
|
@@ -2243,28 +2265,41 @@ export class Viewer extends ViewerBase{
|
|
|
|
|
|
if(!view.active)return
|
|
|
var left,bottom,width,height
|
|
|
- if(!params_.target){
|
|
|
+ {
|
|
|
left = Math.floor(renderSize.x * view.left)
|
|
|
bottom = Math.floor(renderSize.y * view.bottom)
|
|
|
- width = view.resolution.x // 用的是client的width和height
|
|
|
- height = view.resolution.y
|
|
|
- this.renderer.setViewport(left, bottom, width, height) //规定视口,影响图形变换
|
|
|
|
|
|
- let scissorTest = view.width<1 || view.height<1
|
|
|
- scissorTest && this.renderer.setScissor( left, bottom, width, height );//规定渲染范围
|
|
|
- this.renderer.setScissorTest( scissorTest );//开启WebGL剪裁测试功能,如果不开启,.setScissor方法设置的范围不起作用 | width==1且height==1时开启会只有鼠标的地方刷新,很奇怪
|
|
|
+ if(params_.target){//有target时最好viewport是专门建出来的
|
|
|
+ width = Math.floor(renderSize.x * view.width)
|
|
|
+ height = Math.floor(renderSize.y * view.height)
|
|
|
+ }else{
|
|
|
+ width = view.resolution.x // 用的是client的width和height
|
|
|
+ height = view.resolution.y
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ 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.scissorTest = scissorTest
|
|
|
+ }else{
|
|
|
+ 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时开启会只有鼠标的地方刷新,很奇怪
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
|
|
|
- }
|
|
|
-
|
|
|
- /* needSResize && this.emitResizeMsg({ //resize everything such as lines targets
|
|
|
- resolution: new THREE.Vector2(width,height),
|
|
|
- }); */
|
|
|
- needSResize && this.emitResizeMsg(view)
|
|
|
+
|
|
|
+
|
|
|
+ needSResize && this.emitResizeMsg({resolution: new THREE.Vector2(width,height), left:view.left, bottom:view.bottom })//resize everything such as lines targets
|
|
|
|
|
|
viewer.dispatchEvent({type: "render.begin", viewer: viewer, viewport:view, params });
|
|
|
|
|
|
if(view.render){
|
|
|
- view.render({renderer:this.renderer, renderOverlay: this.renderOverlay.bind(this) })
|
|
|
+ view.render({target: params_.target, renderer:this.renderer, renderOverlay: this.renderOverlay.bind(this) })
|
|
|
}
|
|
|
|
|
|
|
|
@@ -2272,9 +2307,9 @@ export class Viewer extends ViewerBase{
|
|
|
|
|
|
if(!view.noPointcloud ){
|
|
|
|
|
|
- if(!params.target){
|
|
|
+ //if(!params.target){
|
|
|
params.width = width; params.height = height;
|
|
|
- }
|
|
|
+ //}
|
|
|
|
|
|
|
|
|
|
|
@@ -2298,7 +2333,7 @@ export class Viewer extends ViewerBase{
|
|
|
this.updateViewPointcloud(params.camera, new THREE.Vector2(params.width,params.height), true)
|
|
|
pRenderer.clear(params);
|
|
|
pRenderer.render(params);
|
|
|
- this.renderer.setRenderTarget(null)
|
|
|
+
|
|
|
|
|
|
|
|
|
}
|
|
@@ -2310,7 +2345,7 @@ export class Viewer extends ViewerBase{
|
|
|
this.dispatchEvent({type: "render.end", viewer: this, viewport:view });
|
|
|
})
|
|
|
|
|
|
-
|
|
|
+ this.renderer.setRenderTarget(null)
|
|
|
|
|
|
|
|
|
}
|
|
@@ -2346,14 +2381,14 @@ export class Viewer extends ViewerBase{
|
|
|
}
|
|
|
|
|
|
|
|
|
-
|
|
|
+ this.setCameraLayers(camera, ['volume','transformationTool'])
|
|
|
this.renderer.render(this.clippingTool.sceneVolume, camera);
|
|
|
this.renderer.render(this.transformationTool.scene, camera);
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
+
|
|
|
|
|
|
}
|
|
|
+
|
|
|
+
|
|
|
|
|
|
|
|
|
setCameraLayers(camera, enableLayers){//add
|
|
@@ -2378,8 +2413,7 @@ export class Viewer extends ViewerBase{
|
|
|
})
|
|
|
}
|
|
|
|
|
|
-
|
|
|
-
|
|
|
+
|
|
|
render(params){//add params
|
|
|
if(Potree.measureTimings) performance.mark("render-start");
|
|
|
|
|
@@ -2403,6 +2437,180 @@ export class Viewer extends ViewerBase{
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+
|
|
|
+
|
|
|
+ startScreenshot(info={}, width=800, height=400, compressRatio){//add
|
|
|
+ //可能需要一定时间,因在全景图模式需要加载完图片,所以返回一个promise
|
|
|
+
|
|
|
+ let deferred = $.Deferred();
|
|
|
+ var screenshot = ()=>{
|
|
|
+ var { buffer } = this.makeScreenshot( new THREE.Vector2(width,height) );
|
|
|
+
|
|
|
+ var dataUrl = Potree.Utils.pixelsArrayToDataUrl(buffer, width, height, compressRatio)
|
|
|
+
|
|
|
+ if(!Potree.settings.isOfficial){
|
|
|
+ Common.downloadFile(dataUrl, 'screenshot.jpg')
|
|
|
+ }
|
|
|
+ deferred.resolve(dataUrl)
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ let mapViewport = this.mapViewer.viewports[0]
|
|
|
+ let mainViewport = this.mainViewport
|
|
|
+ let oldStates = {
|
|
|
+ attachedToViewer : this.mapViewer.attachedToViewer,
|
|
|
+ viewports : [mapViewport, mainViewport].map(e=>{
|
|
|
+ return e.clone()
|
|
|
+ }),
|
|
|
+ mapZoom: mapViewport.camera.zoom
|
|
|
+ }
|
|
|
+ if(info.type == 'measure'){//要截图双屏
|
|
|
+
|
|
|
+ this.mapViewer.attachToMainViewer(true, 'measure', 0.5)
|
|
|
+
|
|
|
+ //viewer.updateScreenSize({forceUpdateSize:true, width, height})
|
|
|
+
|
|
|
+ //不同角度截图 得到三维的会不一样,因为focusOnObject是根据方向的
|
|
|
+ let promise = this.focusOnObject(info.measurement, 'measure', 0, /* {mapDont:true} */)
|
|
|
+ promise.done(()=>{
|
|
|
+
|
|
|
+ this.viewports.forEach(e=>{
|
|
|
+ e.view.applyToCamera(e.camera)
|
|
|
+
|
|
|
+ this.dispatchEvent({ //update map
|
|
|
+ type: "camera_changed",
|
|
|
+ camera: e.camera,
|
|
|
+ viewport : e
|
|
|
+ })
|
|
|
+
|
|
|
+ })
|
|
|
+ screenshot()
|
|
|
+
|
|
|
+ })
|
|
|
+
|
|
|
+ }else{
|
|
|
+ screenshot()
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ {
|
|
|
+ //恢复:
|
|
|
+ if(oldStates.attachedToViewer != this.mapViewer.attachedToViewer){
|
|
|
+ if(info.type == 'measure'){
|
|
|
+ this.mapViewer.attachToMainViewer(false)
|
|
|
+ }
|
|
|
+ }
|
|
|
+ mapViewport.camera.zoom = oldStates.mapZoom
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ oldStates.viewports.forEach(old=>{//恢复相机
|
|
|
+ var viewport = [mapViewport, mainViewport].find(v=>v.name == old.name);
|
|
|
+ viewport.left = old.left;
|
|
|
+ viewport.width = old.width;
|
|
|
+ viewport.view.copy(old.view)
|
|
|
+ viewport.view.applyToCamera(viewport.camera);
|
|
|
+
|
|
|
+ })
|
|
|
+
|
|
|
+ viewer.updateScreenSize({forceUpdateSize:true})//更新像素
|
|
|
+
|
|
|
+ oldStates.viewports.forEach(old=>{//恢复相机
|
|
|
+ var viewport = [mapViewport, mainViewport].find(v=>v.name == old.name);
|
|
|
+ this.dispatchEvent({ //update map
|
|
|
+ type: "camera_changed",
|
|
|
+ camera: viewport.camera,
|
|
|
+ viewport : viewport
|
|
|
+ })
|
|
|
+ })
|
|
|
+ }
|
|
|
+
|
|
|
+ return deferred.promise()
|
|
|
+
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ focusOnObject(object, type, duration, o={} ) {
|
|
|
+ //飞向热点、测量线等 。
|
|
|
+ let deferred = $.Deferred();
|
|
|
+ let target = new THREE.Vector3,
|
|
|
+ position = new THREE.Vector3,
|
|
|
+ dis;
|
|
|
+ duration = duration == void 0 ? 2000 : duration;
|
|
|
+ let camera = viewer.scene.getActiveCamera()
|
|
|
+
|
|
|
+ if (type == 'measure') {
|
|
|
+ let bound = new THREE.Box3()
|
|
|
+ object.points.forEach(p => bound.expandByPoint(p))
|
|
|
+
|
|
|
+ let boundSize = bound.getSize(new THREE.Vector3)
|
|
|
+ let {center,radius} = bound.getBoundingSphere({center:new THREE.Vector3}) //用不box的算不准,就保守用sphere了,缺点是无法占满屏,优点是不会靠太近
|
|
|
+ target.copy(object.getCenter())//copy(center)
|
|
|
+
|
|
|
+ let aspect = 1
|
|
|
+
|
|
|
+ if(camera.aspect > aspect){//视野更宽则用bound的纵向来决定
|
|
|
+ dis = radius/ THREE.Math.degToRad(camera.fov / 2)
|
|
|
+ }else{
|
|
|
+ let hfov = cameraLight.getHFOVForCamera(camera, camera.aspect, 1 );
|
|
|
+ dis = radius / THREE.Math.degToRad(hfov / 2)
|
|
|
+ }
|
|
|
+
|
|
|
+ if(o.mapDont || this.mapViewer.attachedToViewer){
|
|
|
+ this.mapViewer.fitToBound(target.clone(), boundSize.clone().multiplyScalar(2), duration)
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ if(Potree.settings.displayMode == 'showPointCloud'){
|
|
|
+ let dir = new THREE.Vector3().subVectors(camera.position, target).normalize()
|
|
|
+ position.copy(target).add(dir.multiplyScalar(dis))
|
|
|
+
|
|
|
+ }else if(Potree.settings.displayMode == 'showPanos'){
|
|
|
+ let pano = viewer.images360.fitPanoTowardPoint({
|
|
|
+ point : target,
|
|
|
+ bestDistance : dis * 0.5 //乘以小数是为了尽量靠近
|
|
|
+ })
|
|
|
+ pano && viewer.images360.flyToPano({pano, target, duration, deferred })
|
|
|
+ return deferred
|
|
|
+ }
|
|
|
+ } else if (type == 'tag') {
|
|
|
+ const bestDistance = 2
|
|
|
+ target.copy(object.position)
|
|
|
+ if(Potree.settings.displayMode == 'showPointCloud'){
|
|
|
+ dis = bestDistance
|
|
|
+ let dir = new THREE.Vector3().subVectors(camera.position, target).normalize()
|
|
|
+ position.copy(target).add(dir.multiplyScalar(dis))
|
|
|
+
|
|
|
+ }else if(Potree.settings.displayMode == 'showPanos'){
|
|
|
+ let pano = viewer.images360.fitPanoTowardPoint({
|
|
|
+ point : target,
|
|
|
+ bestDistance //越近越好,但不要太近,bestDistance左右差不多
|
|
|
+ })
|
|
|
+ pano && viewer.images360.flyToPano({pano, target, duration, deferred })
|
|
|
+ return deferred
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ viewer.scene.view.setView(position, target, duration, ()=>{
|
|
|
+ deferred.resolve()
|
|
|
+ })
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ return deferred.promise()
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
resolveTimings(timestamp){
|
|
|
if(Potree.measureTimings){
|
|
|
if(!this.toggle){
|
|
@@ -2604,155 +2812,6 @@ export class Viewer extends ViewerBase{
|
|
|
|
|
|
}
|
|
|
|
|
|
- startScreenshot(info={}, width=800, height=400, compressRatio){//add
|
|
|
- //可能需要一定时间,因在全景图模式需要加载完图片,所以返回一个promise
|
|
|
-
|
|
|
- let deferred = $.Deferred();
|
|
|
- var screenshot = ()=>{
|
|
|
- var { buffer } = this.makeScreenshot( new THREE.Vector2(width,height) );
|
|
|
-
|
|
|
- var dataUrl = Potree.Utils.pixelsArrayToDataUrl(buffer, width, height, compressRatio)
|
|
|
-
|
|
|
- Common.downloadFile(dataUrl, 'screenshot.jpg')
|
|
|
-
|
|
|
- deferred.resolve()
|
|
|
- }
|
|
|
- let oldStates = {
|
|
|
- attachedToViewer : this.mapViewer.attachedToViewer,
|
|
|
- views : this.viewports.map(e=>{
|
|
|
- return {
|
|
|
- view : e.view.clone(),
|
|
|
- name : e.name
|
|
|
- }
|
|
|
- })
|
|
|
- }
|
|
|
- if(info.type == 'measure'){//要截图双屏
|
|
|
- if(!oldStates.attachedToViewer){
|
|
|
- this.mapViewer.attachToMainViewer(true, 'measure')
|
|
|
- }
|
|
|
- viewer.updateScreenSize({forceUpdateSize:true, width, height})
|
|
|
-
|
|
|
-
|
|
|
- let promise = this.focusOnObject(info.measurement, 'measure', 0)
|
|
|
- promise.done(()=>{
|
|
|
- screenshot()
|
|
|
-
|
|
|
- })
|
|
|
-
|
|
|
- }else{
|
|
|
- screenshot()
|
|
|
- }
|
|
|
-
|
|
|
- /* const aspect = width / height;
|
|
|
- camera.aspect = aspect
|
|
|
- camera.updateProjectionMatrix() */
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
- {
|
|
|
- //恢复:
|
|
|
- if(oldStates.attachedToViewer != this.mapViewer.attachedToViewer){
|
|
|
- if(info.type == 'measure'){
|
|
|
- this.mapViewer.attachToMainViewer(false)
|
|
|
- }
|
|
|
-
|
|
|
- }
|
|
|
- oldStates.views.forEach(e=>{//恢复相机
|
|
|
- var viewport = this.viewports.find(v=>v.name == e.name);
|
|
|
- viewport.view.applyToCamera(viewport.camera);
|
|
|
-
|
|
|
- })
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
- }
|
|
|
-
|
|
|
- return deferred.promise()
|
|
|
-
|
|
|
-
|
|
|
- }
|
|
|
-
|
|
|
-
|
|
|
- focusOnObject(object, type, duration ) {
|
|
|
- //飞向热点、测量线等 。
|
|
|
- let deferred = $.Deferred();
|
|
|
- let target = new THREE.Vector3,
|
|
|
- position = new THREE.Vector3,
|
|
|
- dis;
|
|
|
- duration = duration == void 0 ? 2000 : duration;
|
|
|
- let camera = viewer.scene.getActiveCamera()
|
|
|
-
|
|
|
- if (type == 'measure') {
|
|
|
- let bound = new THREE.Box3()
|
|
|
- object.points.forEach(p => bound.expandByPoint(p))
|
|
|
-
|
|
|
- let boundSize = bound.getSize(new THREE.Vector3)
|
|
|
- let {center,radius} = bound.getBoundingSphere({center:new THREE.Vector3}) //用不box的算不准,就保守用sphere了,缺点是无法占满屏,优点是不会靠太近
|
|
|
- target.copy(object.getCenter())//copy(center)
|
|
|
-
|
|
|
- let aspect = 1
|
|
|
-
|
|
|
- if(camera.aspect > aspect){//视野更宽则用bound的纵向来决定
|
|
|
- dis = radius/ THREE.Math.degToRad(camera.fov / 2)
|
|
|
- }else{
|
|
|
- let hfov = cameraLight.getHFOVForCamera(camera, camera.aspect, 1 );
|
|
|
- dis = radius / THREE.Math.degToRad(hfov / 2)
|
|
|
- }
|
|
|
-
|
|
|
-
|
|
|
- if(Potree.settings.displayMode == 'showPointCloud'){
|
|
|
-
|
|
|
-
|
|
|
- let dir = new THREE.Vector3().subVectors(camera.position, target).normalize()
|
|
|
- position.copy(target).add(dir.multiplyScalar(dis))
|
|
|
-
|
|
|
- if(this.mapViewer.attachedToViewer){
|
|
|
- this.mapViewer.fitToBound(target.clone(), boundSize.clone().multiplyScalar(2), duration)
|
|
|
- }
|
|
|
-
|
|
|
- }else if(Potree.settings.displayMode == 'showPanos'){
|
|
|
- let pano = viewer.images360.fitPanoTowardPoint({
|
|
|
- point : target,
|
|
|
- bestDistance : dis * 0.5 //乘以小数是为了尽量靠近
|
|
|
- })
|
|
|
- pano && viewer.images360.flyToPano({pano, target, duration, deferred })
|
|
|
- return
|
|
|
- }
|
|
|
- } else if (type == 'tag') {
|
|
|
- const bestDistance = 2
|
|
|
- target.copy(object.position)
|
|
|
- if(Potree.settings.displayMode == 'showPointCloud'){
|
|
|
- dis = bestDistance
|
|
|
- let dir = new THREE.Vector3().subVectors(camera.position, target).normalize()
|
|
|
- position.copy(target).add(dir.multiplyScalar(dis))
|
|
|
-
|
|
|
- }else if(Potree.settings.displayMode == 'showPanos'){
|
|
|
- let pano = viewer.images360.fitPanoTowardPoint({
|
|
|
- point : target,
|
|
|
- bestDistance //越近越好,但不要太近,bestDistance左右差不多
|
|
|
- })
|
|
|
- pano && viewer.images360.flyToPano({pano, target, duration, deferred })
|
|
|
- return
|
|
|
- }
|
|
|
-
|
|
|
- }
|
|
|
-
|
|
|
- viewer.scene.view.setView(position, target, duration, ()=>{
|
|
|
- deferred.resolve()
|
|
|
- })
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
- return deferred.promise()
|
|
|
- }
|
|
|
-
|
|
|
|
|
|
|
|
|
};
|