123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646 |
- import * as THREE from "../../../libs/three.js/build/three.module.js";
- import {MapLayer} from './Map'
- import {FirstPersonControls} from '../../navigation/FirstPersonControls'
- import {View} from "../View.js";
- import Viewport from "../Viewport.js";
- import {InputHandler} from "../../navigation/InputHandler.js";
- import {ViewerBase} from "../viewerBase.js"
- import math from "../../utils/math.js";
- //import CursorDeal from '../utils/CursorDeal'
- import {Images360} from '../../modules/Images360/Images360'
- import Common from '../../utils/Common'
- import {transitions, easing, lerp} from "../../utils/transitions.js";
- import {config } from "../../settings.js";
- /* var centerCross = new THREE.Mesh(new THREE.SphereGeometry(1, 4, 4),new THREE.MeshBasicMaterial({
- transparent:true, color:"#ff0000", opacity:0.5
- })); */
- /* const mapHeight = -1000;//要比点云低。最低
- const cameraHeight = 1000; //最高 */
- const panosHeight = config.map.mapHeight + 100 //要比点云低 (marker)
- const cursorHeight = 0;//比地图高就行
- const routeLayerHeight = config.map.mapHeight + 105
- const texLoader = new THREE.TextureLoader()
- const planeGeo = new THREE.PlaneBufferGeometry(1,1)
- const markerSize = 1;
- var initCameraFeildWidth = 50
- var panoMarkerMats
-
- export class MapViewer extends ViewerBase{
- constructor(dom){
- super(dom, {
- clearColor: Potree.config.mapBG,
- name: 'mapViewer'
- })
- this.visible = true
- this.initScene()
-
-
- this.mapLayer = new MapLayer(this, this.viewports[0])
- this.scene.add(this.mapLayer.sceneGroup)
- this.mapLayer.sceneGroup.position.setZ(Potree.config.map.mapHeight)
- this.mapRatio = 0.5
- this.splitDir = 'leftRight'
-
-
- //this.scene.add(centerCross)
-
-
- viewer.addEventListener("camera_changed", (e)=>{
- if(e.viewport == viewer.mainViewport) this.updateCursor()
- else this.updateWhenAtViewer()
- })
-
-
- //viewer.addEventListener("global_mousemove", this.updateWhenAtViewer.bind(this)) //鼠标移动时reticule也动,所以直接就needRender
- viewer.reticule.addEventListener('update',(e)=>{
- if(this.attachedToViewer)this.needRender = true
- })
-
-
- viewer.scene.addEventListener("360_images_added", this.addPanos.bind(this))
-
-
- viewer.addEventListener("loadPointCloudDone", this.initProjection.bind(this))
-
- this.addEventListener('global_click',(e)=>{
- if(!e.isTouch && e.button != THREE.MOUSE.LEFT)return
- this.updateClosestPano(e.intersectPoint)
- })
-
-
-
- this.addEventListener('add',(e)=>{//添加其他mesh
- this.scene.add(e.object)
- if(e.name == 'route'){
- e.object.position.z = routeLayerHeight
- }
- viewer.setObjectLayers(e.object, 'mapObjects' )
- })
-
-
-
-
-
- if(!Potree.settings.isOfficial){
- let domRoot = viewer.renderer.domElement.parentElement;
- let elAttach = $("<input type='button' value='map绑定'></input>");
- elAttach.css({
- position : "absolute",
- right : '80%',
- bottom: '20px',
- zIndex: "10000",
- fontSize:'1em', color:"black",
- background:'rgba(255,255,255,0.8)',
- })
- let state = false
- elAttach.on("click", () => {
- state = !state
- this.attachToMainViewer(state, 'measure')
- elAttach.val(state ? 'map分离':'map绑定')
- });
- domRoot.appendChild(elAttach[0]);
-
-
- }
-
- }
-
-
-
-
-
- waitLoadDone(callback){//确保加载完后执行
- if(this.mapLayer.loadingInProgress == 0){
- callback()
- }else{
- var f = ()=>{
- callback()
- this.mapLayer.removeEventListener('loadDone', f)
- }
- this.mapLayer.addEventListener('loadDone', f)
- }
-
- }
-
- addListener(images360){
- images360.addEventListener('flyToPano',e=>{
- let toPano = e.toPano
- if(toPano.dontMoveMap) return
-
- /* transitions.start(lerp.vector(this.view.position, toPano.pano.position.clone().setZ(cameraHeight),
-
- (pos, progress)=>{
-
- }), toPano.duration, null, 0, easing[toPano.easeName] ); */
- let boundSize// = new THREE.Vector2(10,10)
-
- this.moveTo(toPano.pano.position.clone().setZ(Potree.config.map.cameraHeight), boundSize, toPano.duration, toPano.easeName)
- })
-
-
- }
-
-
-
- initProjection(){
- this.started = true
- this.mapLayer.initProjection()
-
- }
-
- initScene(){
- let w = initCameraFeildWidth
- let width = this.renderArea.clientWidth;
- let height = this.renderArea.clientHeight;
- //let aspect = width / height
- this.camera = new THREE.OrthographicCamera(-width/2,width/2,height/2,-height/2/* -w/2, w/2, w/2/aspect, -w/2/aspect */, 0.01, 10000);
- this.camera.zoom = width / w //zoom越大视野越小
- //this.camera.position.set(0,0,10);
- this.camera.up.set(0,0,1)
- //this.camera.lookAt(new THREE.Vector3())
- //this.camera.updateMatrixWorld()
-
- this.view = new View();
- this.view.position.set(0,0,Potree.config.map.cameraHeight);
- this.view.lookAt(0,0,0)
- this.setViewLimit('standard')
-
- let viewport = new Viewport( this.view, this.camera, {
- left:0, bottom:0, width:1, height: 1, name:'mapViewport'
- })
- viewport.axis = ["x","y"]
- viewport.axisSign = [1,1]
-
- viewport.noPointcloud = true; //不要渲染点云
- viewport.render = this.render.bind(this)//标志给mainView渲染
- //viewport.unableDepth = true //depthBasicMaterial等在此viewport中不开启depth
-
-
-
- this.viewports = [viewport]
-
-
-
-
- this.controls = new FirstPersonControls(this, this.viewports[0]);
- this.controls.setEnable(true)
- this.scene = new THREE.Scene();
-
-
-
- this.inputHandler = new InputHandler(this, this.scene);
- this.inputHandler.name = 'mapInputHandler'
- //this.inputHandler.addInputListener(this.controls);
- this.inputHandler.registerInteractiveScene(this.scene);//interactiveScenes
-
- this.viewports[0].interactiveScenes = this.inputHandler.interactiveScenes;//供viewer的inputHandler使用
-
- var cursor = new THREE.Mesh(planeGeo, new THREE.MeshBasicMaterial({
- transparent:true,
- opacity:0.9,
- depthTest : false, //防止透明冲突
- map: texLoader.load(Potree.resourcePath+'/textures/pic_location128.png' )
- }))
- cursor.position.set(0,0,cursorHeight);
-
-
- this.cursor = cursor
-
- this.scene.add(cursor)
- viewer.setObjectLayers(this.scene, 'mapObjects' )
- }
-
- setViewLimit(state){//设置边界,当编辑空间模型等时要解禁
- let setting = Potree.config.OrthoCameraLimit[state]
- if(setting){
- this.view.limitBound = new THREE.Box3().copy(setting.posBound)
- this.camera.zoomLimit = $.extend({},setting.zoom);
- }else{
- this.view.limitBound = null
- this.camera.zoomLimit = null
- }
- }
-
- updateCursor(){
-
- var scale = math.getScaleForConstantSize( {//规定下最小最大像素
- minSize : 80, maxSize : 200, nearBound : initCameraFeildWidth*0.1 , farBound : initCameraFeildWidth*2,
- camera:this.camera , position: this.cursor.getWorldPosition(new THREE.Vector3()),
- resolution: this.viewports[0].resolution//2
- })
- this.cursor.scale.set(scale, scale, scale);//当地图缩放时
- this.cursor.position.copy(viewer.mainViewport.camera.position).setZ(cursorHeight)//当场景镜头旋转移动时
- this.cursor.rotation.z = viewer.mainViewport.view.yaw
- this.needRender = true
- }
-
- addPanos(e){
- var panosGroup = new THREE.Object3D;
- panoMarkerMats = {
- default: new THREE.MeshBasicMaterial({
- transparent:true,
- opacity: 0.5,
- map: texLoader.load(Potree.resourcePath+'/textures/map_marker.png' ),
- }),
- selected: new THREE.MeshBasicMaterial({
- transparent:true,
- opacity: 1,
- map: texLoader.load(Potree.resourcePath+'/textures/map_marker.png' ),
- })
- }
-
-
- e.images.panos.forEach(pano=>{
- pano.mapMarker = new THREE.Mesh(planeGeo, panoMarkerMats.default);
- pano.mapMarker.position.copy(pano.position).setZ(0)
- pano.mapMarker.scale.set(markerSize,markerSize,markerSize)
- pano.mapMarker.name = 'mapMarker'
- panosGroup.add(pano.mapMarker);
-
-
- let mouseover = (e)=>{
- if(!e.byMap){
- pano.mapMarker.material = panoMarkerMats.selected
- if(!e.byMainView) pano.dispatchEvent({type: "hoverOn", byMap:true})
- this.needRender = true
- }
- }
-
- let mouseleave = (e)=>{
- if(!e.byMap){
- pano.mapMarker.material = panoMarkerMats.default
- if(!e.byMainView) pano.dispatchEvent({type: "hoverOff", byMap:true})
- this.needRender = true
- }
- }
-
-
- pano.mapMarker.addEventListener('mouseover', mouseover);
- pano.mapMarker.addEventListener('mouseleave', mouseleave);
-
- pano.addEventListener('hoverOn', mouseover)
- pano.addEventListener('hoverOff', mouseleave)
-
- let onclick = (e)=>{
- viewer.images360.flyToPano(pano)
- }
- pano.mapMarker.addEventListener('click', onclick);
-
- pano.addEventListener('isVisible',(e)=>{//是否显示该点的mesh(不显示也能走)
- //console.log('panoMarker isVisible', pano.id, e.visible)
- viewer.updateVisible(pano.mapMarker, 'panoVisible', e.visible )
- this.needRender = true
-
- })
- pano.addEventListener('rePos',(e)=>{
- pano.mapMarker.position.copy(pano.position).setZ(0)
- })
- })
- this.scene.add(panosGroup)
- panosGroup.position.z = panosHeight
- this.panosGroup = panosGroup
- viewer.setObjectLayers(panosGroup, 'mapObjects' )
-
-
- /* e.images.on('markersDisplayChange', (show)=>{
- panosGroup.visible = show
- this.needRender = true
- }) */
-
- //-------
-
- //this.fitPanosToViewport()
- this.initFitView()
- }
-
-
-
- updateClosestPano(intersect){
- if(viewer.images360.flying)return;
- intersect = intersect && intersect.orthoIntersect
- if(!intersect)return
-
- intersect = intersect.clone().setZ(0)
-
- const minDis = 20 //距离鼠标不能太远
-
- var filterFuncs = [
- (pano)=>{
- return pano.position.clone().setZ(0).distanceTo(intersect) < minDis
- },
- Images360.filters.isEnabled(),
-
- Images360.filters.isVisible(),//只走显示的点,否则会走到别的层
- ];
-
-
-
-
-
-
- var pano = Common.find(viewer.images360.panos, filterFuncs, [Images360.sortFunctions.floorDisSquaredToPoint(intersect)]);
- if (pano && pano != viewer.images360.currentPano ) {
- viewer.images360.flyToPano(pano)
-
- }
-
- }
-
-
- fitPanosToViewport(){//使所有漫游点占满viewport
-
- //var w = viewer.bound.boundSize.x;
- var boundSize = viewer.images360.bound.size.clone().multiplyScalar(1.1);
- boundSize.max(new THREE.Vector3(4,4,4))
- let endPosition = viewer.images360.bound.center.clone()
- this.moveTo(endPosition, boundSize, 0)
- }
- fitToPointcloud(pointcloud, duration=400){
- var boundSize = pointcloud.bound.getSize(new THREE.Vector3)/* .multiplyScalar(1.1); */
- boundSize.max(new THREE.Vector3(4,4,4))
- let endPosition = pointcloud.bound.getCenter(new THREE.Vector3)
- this.moveTo(endPosition, boundSize, duration) //给点duration去变化 否则地图放大后所占的还是很小
- }
- initFitView(){
- let dis = 5 , px = 70 //地图上px像素长度代表的距离为dis //px是手动缩放到5m后发现是这个长度
- let zoom = px / dis;
- this.camera.zoom = zoom
- this.moveTo(viewer.images360.position/* viewer.images360.bound.center */)
- this.camera.updateProjectionMatrix()
- }
-
- fitToDatasets(datasets){
- let bound = new THREE.Box3;
- datasets.forEach(e=>bound.union(e.bound))
- let center = bound.getCenter(new THREE.Vector3)
- let size = bound.getSize(new THREE.Vector3)
-
- this.moveTo(center, size, 200 ) //给duration是为了顺应视口大小改变,缓冲
- }
-
- moveTo(endPosition, boundSize, duration=0, easeName){//前两个参数有xy即可
- endPosition = new THREE.Vector3(endPosition.x,endPosition.y,Potree.config.map.cameraHeight)
- this.view.moveOrthoCamera(this.viewports[0], {endPosition, boundSize }, duration, easeName)
-
-
-
-
- /* let endZoom, startZoom = this.camera.zoom
-
- //修改相机为bound中心,这样能看到全部(宽度范围内)
-
- this.view.setView({ position:endPosition, duration,
- callback:()=>{//done
-
- },
- onUpdate:(progress)=>{
- if(boundSize){
- let aspect = boundSize.x / boundSize.y
- let w, h;
-
- if(this.camera.aspect > aspect){//视野更宽则用bound的纵向来决定
- h = boundSize.y
- //w = h * this.camera.aspect
- endZoom = this.viewports[0].resolution.y / h
- }else{
- w = boundSize.x;
- //h = w / this.camera.aspect
- endZoom = this.viewports[0].resolution.x / w
- }
- //onUpdate时更新endzoom是因为画布大小可能更改
-
-
- this.camera.zoom = endZoom * progress + startZoom * (1 - progress)
- this.camera.updateProjectionMatrix()
- }
- },
-
- Easing:easeName
-
- }) */
-
-
- }
-
-
-
-
- updateWhenAtViewer(e){
- if(this.attachedToViewer){
- if(this.started) this.mapLayer.update()
-
- this.updateCursor()
- this.needRender = true
- }
- }
-
- update(delta, areaSize ){
- if(!this.visible && !this.attachedToViewer )return
-
-
- if(this.attachedToViewer){
- if(this.mapLayer.needUpdate){//必须更新。(较少触发)
- this.updateWhenAtViewer()
- }
- return
- }
-
-
- this.updateScreenSize()
-
- this.controls.update(delta);
- this.view.applyToCamera(this.camera)
-
-
- let changed = this.cameraChanged()
-
-
- if(this.started && (changed || this.mapLayer.needUpdate))this.mapLayer.update()
-
- if(changed /*|| || this.needRender */){
- this.dispatchEvent({
- type: "camera_changed",
- camera: this.camera,
- viewport : this.viewports[0]
- })
-
- this.needRender = true
- this.updateCursor()//更改大小
- }
- this.render()
-
- }
-
- attachToMainViewer(state, desc, mapRatio=0.5, options={}){//转移到viewer中。测量时展示or截图需要
-
- if(!Potree.settings.isOfficial)this.renderArea.style.display = state ? 'none':'block'
-
- if(state){
- this.enabledOld = this.enabled
- this.enabled = true
-
- if(mapRatio != 'dontSet'){
- this.changeSplitScreenDir(options.dir, mapRatio)
-
- if(this.attachedToViewer){
- //this.fitPanosToViewport()
- viewer.updateScreenSize({forceUpdateSize:true})
- return
- }
- viewer.viewports = [viewer.mainViewport, viewer.mapViewer.viewports[0] ];//因为mainViewer的相机变化会触发map的变化,所以先渲染mainViewer
- }
-
-
- if(desc == 'measure') this.inputHandler.registerInteractiveScene(viewer.measuringTool.scene);//虽然用的是viewer的inputHandler,但借用了this.inputHandler的interactiveScenes
- else if(desc == 'split4Screens') {
- this.inputHandler.registerInteractiveScene(viewer.scene.scene);
- }
-
- }else{
- if(!this.attachedToViewer)return
-
- viewer.mainViewport.left = 0;
- viewer.mainViewport.bottom = 0;
- viewer.mainViewport.width = 1;
- viewer.mainViewport.height = 1;
-
- this.viewports[0].width = 1;
- this.viewports[0].bottom = 0;
- this.viewports[0].height = 1;
- this.viewports[0].left = 0;
-
- this.inputHandler.unregisterInteractiveScene(viewer.measuringTool.scene);
- this.inputHandler.unregisterInteractiveScene(viewer.scene.scene);
- viewer.viewports = [viewer.mainViewport]
- this.updateScreenSize({forceUpdateSize:true}) //更新相机projectionMatrix
- }
-
- //if(desc == 'measure')this.renderMeasure = state
- this.attachedToViewer = state
-
-
-
-
-
- viewer.updateScreenSize({forceUpdateSize:true})
-
-
- //mapRatio != 'dontSet' && !options.dontFit && this.moveTo(...)//要写在updateScreenSize后面,因为要根据视图大小来fit
- if(options.moveToCurrentPos){
- let boundSize = new THREE.Vector2(10,10)
- let duration = 1000
- this.moveTo(viewer.images360.position.clone(), boundSize, duration)
- }
- this.needRender = true
- }
-
- changeSplitScreenDir(dir, mapRatio){//左右 | 上下
- //if(!dir || dir == this.dir)return
- if(dir )this.splitDir = dir
- this.updateSplitSize(mapRatio)
- /* if(this.attachedToViewer){ //如果已经分屏了,中途修改方向的话……
- this.updateSplitSize()
- } */
- }
- updateSplitSize(mapRatio){
- if(mapRatio != void 0) this.mapRatio = mapRatio
-
- //console.log(this.mapRatio)
-
- if(this.splitDir == 'leftRight'){//地图在左方
- viewer.mainViewport.left = this.mapRatio
- viewer.mainViewport.width = 1-this.mapRatio
- this.viewports[0].width = this.mapRatio;
-
- viewer.mainViewport.bottom = this.viewports[0].bottom = 0
- viewer.mainViewport.height = this.viewports[0].height = 1
-
- }else if(this.splitDir == 'upDown'){ //地图在下方
- viewer.mainViewport.bottom = this.mapRatio
- viewer.mainViewport.height = 1-this.mapRatio
- this.viewports[0].height = this.mapRatio;
-
- viewer.mainViewport.left = this.viewports[0].left = 0
- viewer.mainViewport.width = this.viewports[0].width = 1
-
- }
- if(this.attachedToViewer){
- viewer.updateScreenSize({forceUpdateSize:true})
- }
- }
-
- render(params={}){
-
- if(!this.visible && !this.attachedToViewer || !this.needRender && !params.force)return
-
- let renderer = params.renderer || this.renderer
-
- if(params.target){
- renderer.setRenderTarget(params.target)
- }
- /* if(params.resize){
- this.emitResizeMsg(new THREE.Vector2(params.width,params.height, viewport:params.viewport))
- } */
- params.clear ? params.clear() : renderer.clear();
-
- if(!this.attachedToViewer){
- viewer.dispatchEvent({type: "render.begin", viewer: this, viewport:this.viewports[0], params });
- }
-
- viewer.setCameraLayers(this.camera, ['map','mapObjects' , 'bothMapAndScene' ])
-
- if(this.mapGradientBG){//渲染背景
- viewer.scene.cameraBG.layers.set(Potree.config.renderLayers.bg);
- renderer.render(viewer.scene.scene, viewer.scene.cameraBG);
- }
-
- renderer.render(this.scene, this.camera);
- renderer.render(viewer.scene.scene, this.camera);
-
- //测量线等
- //params.renderOverlay && params.renderOverlay({camera:this.camera, isMap:true, viewport: this.viewports[0] })//其余如reticule 等场景层
- params.renderOverlay && params.renderOverlay( $.extend({}, params, { isMap:true }))
-
-
- renderer.setRenderTarget(null)
-
- this.needRender = false
-
- }
-
-
- /* render(){
-
- let camera = viewer.scene.getActiveCamera();
- viewer.scene.view.position.x += 0.01
- viewer.setCameraLayers(camera, ['sceneObjects','marker','reticule','skybox' ])
- this.renderer.render(viewer.scene.scene, camera);
- } */
-
-
-
- }
- //本地调试地图白屏是因为代码自动更新了 但没刷新
|