import {deepMerge, convertPosition} from "../util"; export default (hnMap: any) => { const defaultOption = { id: "", name: "", url: "", position: null, scale: 1, flyTo: false, }; class mars3d_class { type: any = "pointCloud"; id: any = null; option: any = JSON.parse(JSON.stringify(defaultOption)); config: any = null; layerEntity: any = null; constructor(option: any) { this.id = option.id; deepMerge(this.option, option); this.config = this.formatConfig(this.option); this.layerEntity = new mars3d.layer.TilesetLayer(this.config); } formatConfig(option: any) { return { id: option.id, name: option.name, url: option.url, position: option.position, scale: option.scale, attr: { name: option.name, }, flyTo: option.flyTo, }; } set(option: any) { deepMerge(this.option, option); this.config = this.formatConfig(this.option); this.layerEntity.setOptions(this.config); } destroy() { this.layerEntity.remove(true); hnMap.map.map.layerList = hnMap.map.map.layerList.filter( (v: any) => v.id !== this.id ); } // 添加属性弹窗 addPopupByAttr() { this.layerEntity.bindPopup((event: any) => { const data = {name: event.layer.name}; return mars3d.Util.getTemplateHtml({ title: "详情", template: "all", attr: data, }); }); } flyTo() { this.layerEntity.flyTo(); } } class gaode_class { constructor(option: any) { throw new Error("高德地图不支持点云功能"); } } class siji_class { type: any = "pointCloud"; id: any = null; option: any = JSON.parse(JSON.stringify(defaultOption)); config: any = null; layerEntity: any = null; THREE: any = null; camera: any = null; scene: any = null; renderer: any = null; modelTransform: any = null; constructor(option: any) { this.id = option.id; deepMerge(this.option, option); this.config = this.formatConfig(this.option); } // 传入角度值(0-360度),转换为弧度 calculateRotationFromDegrees(angleInDegrees: any) { // 将角度转换为弧度,Three.js中Z轴旋转是顺时针的 const rotateZ = (angleInDegrees * Math.PI) / 180; return [0, 0, rotateZ]; } formatConfig(option: any) { var modelOrigin = convertPosition([ option.position.lng, option.position.lat, ]); var modelAltitude = option.position.alt; var modelRotate = this.calculateRotationFromDegrees(option.rotation); var modelScale = option.scale * 1e-6; var modelTransform = { translateX: SGMap.MercatorCoordinate.fromLngLat( modelOrigin, modelAltitude ).x, translateY: SGMap.MercatorCoordinate.fromLngLat( modelOrigin, modelAltitude ).y, translateZ: SGMap.MercatorCoordinate.fromLngLat( modelOrigin, modelAltitude ).z, rotateX: modelRotate[0], rotateY: modelRotate[1], rotateZ: modelRotate[2], scale: modelScale, }; var THREE = (window as any).THREE; let config: any = {}; config = { id: option.id, type: "custom", renderingMode: "3d", onAdd: function (map: any, gl: any) { this.camera = new THREE.Camera(); this.scene = new THREE.Scene(); var directionalLight = new THREE.DirectionalLight(0xffffff); directionalLight.position.set(0, -70, 100).normalize(); this.scene.add(directionalLight); var directionalLight2 = new THREE.DirectionalLight(0xffffff); directionalLight2.position.set(0, 70, 100).normalize(); this.scene.add(directionalLight2); // var loader = new THREE.GLTFLoader(); var loader = new THREE.ObjectLoader(); let that = this; loader.load( "https://map.sgcc.com.cn/products/js-sdk/v3/assets/model/ZH-SZC3-42.gltf", // function (gltf: any) { function (object: any) { that.scene.add(object); // that.scene.add(gltf.scene); map.flyTo({ center: modelOrigin, // 模型中心坐标 zoom: 18, // 缩放级别,可以调整 pitch: 75, // 倾斜角度 bearing: 0, // 方向角 duration: 2000, // 动画持续时间(毫秒) essential: true, // 表示此动画对用户体验很重要 }); }.bind(that) ); // this.map = map; this.renderer = new THREE.WebGLRenderer({ canvas: map.getCanvas(), context: gl, }); this.renderer.autoClear = false; }, render: function (gl: any, matrix: any) { var rotationX = new THREE.Matrix4().makeRotationAxis( new THREE.Vector3(1, 0, 0), modelTransform.rotateX ); var rotationY = new THREE.Matrix4().makeRotationAxis( new THREE.Vector3(0, 1, 0), modelTransform.rotateY ); var rotationZ = new THREE.Matrix4().makeRotationAxis( new THREE.Vector3(0, 0, 1), modelTransform.rotateZ ); var m = new THREE.Matrix4().fromArray(matrix); var l = new THREE.Matrix4() .makeTranslation( modelTransform.translateX, modelTransform.translateY, modelTransform.translateZ ) .scale( new THREE.Vector3( modelTransform.scale, -modelTransform.scale, modelTransform.scale ) ) .multiply(rotationX) .multiply(rotationY) .multiply(rotationZ); this.camera.projectionMatrix.elements = matrix; this.camera.projectionMatrix = m.multiply(l); this.renderer.state.reset(); this.renderer.render(this.scene, this.camera); }, }; return config; } } // 修复后的 cesium_class class cesium_class { type: string = "pointCloud"; id: string; option: any; graphic: any = null; layerEntity: any = null; private _isReady = false; private _pendingAdd = false; // 标记是否已被 addLayer 调用 constructor(option: any) { this.id = option.id; this.option = JSON.parse(JSON.stringify(defaultOption)); deepMerge(this.option, option); this._initAsync(); } // 异步初始化(不暴露给外部) private async _initAsync() { let modelMatrix; try { // 创建 tileset const tileset = await Cesium.Cesium3DTileset.fromUrl(this.option.url); await tileset.readyPromise; const scale = Cesium.Matrix4.getScale( tileset.root.transform, new Cesium.Cartesian3() ).x; const correctPosition = Cesium.Cartesian3.fromDegrees( this.option.position.lng, this.option.position.lat, this.option.position.alt || 0 ); // 清空 root.transform(防止 ECEF 偏移) tileset.root.transform = Cesium.Matrix4.IDENTITY; // 构建正确 modelMatrix:先定位,再缩放 tileset.modelMatrix = Cesium.Transforms.eastNorthUpToFixedFrame(correctPosition); Cesium.Matrix4.multiplyByUniformScale(tileset.modelMatrix, scale, tileset.modelMatrix); this.layerEntity = tileset; this._isReady = true; // 👇 关键:如果 addLayer 已被调用,现在补上 if (this._pendingAdd) { const viewer = hnMap?.map?.map; if (viewer?.scene?.primitives) { viewer.scene.primitives.add(tileset); if (this.option.flyTo) { this.flyTo() } } } } catch (error) { console.error("点云加载失败:", error); } } // 提供一个同步方法供 map.addLayer 调用 addToScene(viewer: any) { this._pendingAdd = true; // 如果已 ready,立即添加 if (this._isReady && this.layerEntity) { viewer.scene.primitives.add(this.layerEntity); if (this.option.flyTo) { setTimeout(() => this.flyTo(), 100); } } // 否则等待 _initAsync 完成后自动添加(见上面) } // 飞行到点云 flyTo() { const viewer = hnMap?.map?.map; if (viewer && this.layerEntity) { viewer.flyTo(this.layerEntity, {duration: 2.0}); } } // 更新配置 set(option: any) { try { // 更新选项 deepMerge(this.option, option); // 更新显示状态 if (option.show !== undefined && this.layerEntity) { this.layerEntity.show = option.show; } // 更新位置 if (option.position && this.layerEntity) { const position = Cesium.Cartesian3.fromDegrees( option.position.lng, option.position.lat, option.position.alt || 0 ); let modelMatrix = Cesium.Transforms.eastNorthUpToFixedFrame(position); if (option.scale && option.scale !== 1) { const scaleMatrix = Cesium.Matrix4.fromUniformScale(option.scale); modelMatrix = Cesium.Matrix4.multiply( modelMatrix, scaleMatrix, new Cesium.Matrix4() ); } this.layerEntity.modelMatrix = modelMatrix; } } catch (error) { console.error("更新点云配置失败:", error); } } // 销毁 destroy() { if (this.layerEntity) { const viewer = hnMap?.map?.map; viewer?.scene?.primitives?.remove(this.layerEntity); this.layerEntity = null; } } // 添加属性弹窗 addPopupByAttr() { // 点云图层通常不需要弹窗,可根据需要实现 console.log("点云图层添加属性弹窗:", this.id); } } const fn: any = { mars3d: mars3d_class, gaode: gaode_class, siji: siji_class, cesium: cesium_class, }; return fn[hnMap.mapType]; };