|
|
@@ -11,16 +11,90 @@ import "./potree.shim.js"
|
|
|
*/ //注释原因:在start中已经import了,而该文件没被打包在potree.js内, 重复import的话会访问src内的文件
|
|
|
|
|
|
import * as GaussianSplats3D from "../../libs/gaussian/gaussian-splats-3d.module.js";
|
|
|
-
|
|
|
+import {/* bd09togcj02, gcj02tobd09, */wgs84togcj02, gcj02towgs84} from '../../libs/other/coordtransform.js';
|
|
|
|
|
|
import cameraLight from './utils/cameraLight.js'
|
|
|
//多元融合模块
|
|
|
-
|
|
|
+let satellite = true
|
|
|
+let defaultMapProps = satellite ? [
|
|
|
+{url: `//wprd04.is.autonavi.com/appmaptile?lang=zh_cn&size=1&scale=1&style=6&x={x}&y={y}&z={z}&layer=6&token=YOUR_API_KEY`, //style=6是卫星,7是标准
|
|
|
+ maximumLevel: 18 ,
|
|
|
+ name:'高德baseLayer'
|
|
|
+},{
|
|
|
+ url: `//wprd04.is.autonavi.com/appmaptile?lang=zh_cn&size=1&scale=1&style=8&x={x}&y={y}&z={z}&layer=6&token=YOUR_API_KEY`, //style=6是卫星,7是标准
|
|
|
+ maximumLevel: 18,
|
|
|
+ name:'高德textLayer'
|
|
|
+}] : [
|
|
|
+ {url: `//wprd04.is.autonavi.com/appmaptile?lang=zh_cn&size=1&scale=1&style=7&x={x}&y={y}&z={z}&layer=6&token=YOUR_API_KEY`, //style=6是卫星,7是标准
|
|
|
+ maximumLevel: 19 ,
|
|
|
+ name:'高德baseLayer'
|
|
|
+ },
|
|
|
+]
|
|
|
+{
|
|
|
+ // 84坐标转高德 (国外地区用84,所以地理注册时填的是84,我这需要转成高德)
|
|
|
+ const wgs84ToAMap = (pos ) => {
|
|
|
+ const latlng = wgs84togcj02(pos.x, pos.y)
|
|
|
+ return {
|
|
|
+ x: latlng[0],
|
|
|
+ y: latlng[1]
|
|
|
+ }
|
|
|
+ }
|
|
|
+ // 高德坐标转84
|
|
|
+ const aMapToWgs84 = (pos ) => {
|
|
|
+ const latlng = gcj02towgs84(pos.x, pos.y)
|
|
|
+ return {
|
|
|
+ x: latlng[0],
|
|
|
+ y: latlng[1]
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
-var start = function(dom, mapDom, number, fileServer, webSite){ //t-Zvd3w0m
|
|
|
+ window.AMapWith84__ = { //在Potree里setLonlat时不管转不转效果都一样 很奇怪,所以这里改名。只在ces
|
|
|
+ aMapToWgs84, wgs84ToAMap
|
|
|
+ }
|
|
|
+
|
|
|
+}
|
|
|
+
|
|
|
+class AmapMercatorTilingScheme extends Cesium.WebMercatorTilingScheme {
|
|
|
+ constructor(options) {
|
|
|
+ super(options)
|
|
|
+ let projection = new Cesium.WebMercatorProjection()
|
|
|
+ this._projection.project = function(cartographic, result) {
|
|
|
+ //WGS84转GCJ02坐标
|
|
|
+ /* result = gcoord.transform([
|
|
|
+ Cesium.Math.toDegrees(cartographic.longitude),
|
|
|
+ Cesium.Math.toDegrees(cartographic.latitude)
|
|
|
+ ], gcoord.WGS84, gcoord.GCJ02) */
|
|
|
|
|
|
+ result = AMapWith84__.wgs84ToAMap({
|
|
|
+ x: Cesium.Math.toDegrees(cartographic.longitude),
|
|
|
+ y: Cesium.Math.toDegrees(cartographic.latitude)
|
|
|
+ })
|
|
|
|
|
|
+ result = projection.project(new Cesium.Cartographic(Cesium.Math.toRadians(result.x),Cesium.Math.toRadians(result.y)))
|
|
|
+ return new Cesium.Cartesian2(result.x,result.y)
|
|
|
+ }
|
|
|
+ this._projection.unproject = function(cartesian, result) {
|
|
|
+ let cartographic = projection.unproject(cartesian)
|
|
|
+ //GCJ02转WGS84坐标
|
|
|
+ /* result = gcoord.transform([
|
|
|
+ Cesium.Math.toDegrees(cartographic.longitude),
|
|
|
+ Cesium.Math.toDegrees(cartographic.latitude)
|
|
|
+ ], gcoord.GCJ02, gcoord.WGS84) */
|
|
|
+
|
|
|
+ result = AMapWith84__.aMapToWgs84({
|
|
|
+ x: Cesium.Math.toDegrees(cartographic.longitude),
|
|
|
+ y: Cesium.Math.toDegrees(cartographic.latitude)
|
|
|
+ })
|
|
|
+
|
|
|
+ return new Cesium.Cartographic(Cesium.Math.toRadians(result.x),Cesium.Math.toRadians(result.y))
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+var start = function(dom, mapDom, number, fileServer, webSite){ //t-Zvd3w0m
|
|
|
|
|
|
+
|
|
|
+ Potree.settings.showCesium = 1
|
|
|
|
|
|
//设置:
|
|
|
Potree.settings.editType = 'merge'
|
|
|
@@ -36,9 +110,8 @@ var start = function(dom, mapDom, number, fileServer, webSite){ //t-Zvd3w0m
|
|
|
|
|
|
|
|
|
let viewer = new Potree.Viewer(dom , mapDom);
|
|
|
-
|
|
|
- let Alignment = viewer.modules.Alignment
|
|
|
-
|
|
|
+ let cesAspect, ecefToEnuMatrix // , enuToEcefMatrix
|
|
|
+ let {Alignment,MergeEditor} = viewer.modules
|
|
|
viewer.setEDLEnabled(false);
|
|
|
viewer.setFOV(Potree.config.view.fov);
|
|
|
viewer.loadSettingsFromURL();
|
|
|
@@ -60,8 +133,15 @@ var start = function(dom, mapDom, number, fileServer, webSite){ //t-Zvd3w0m
|
|
|
viewer.composer.readTarget = false
|
|
|
}
|
|
|
|
|
|
-
|
|
|
|
|
|
+ viewer.addEventListener('camera_changed', e => {
|
|
|
+ var camera = e.viewport.camera
|
|
|
+ var pos = camera.position
|
|
|
+
|
|
|
+ if (e.viewport.name == 'MainView' || e.viewport.name == 'top' ) {
|
|
|
+ updateMap()
|
|
|
+ }
|
|
|
+ })
|
|
|
|
|
|
if(!Potree.settings.isOfficial){
|
|
|
viewer.loadGUI(() => {
|
|
|
@@ -317,10 +397,12 @@ var start = function(dom, mapDom, number, fileServer, webSite){ //t-Zvd3w0m
|
|
|
}
|
|
|
//viewer.setControls(viewer.orbitControls)
|
|
|
|
|
|
-
|
|
|
+
|
|
|
|
|
|
|
|
|
let tilesetUrls = [
|
|
|
+ //{fromCesium:1, url:'http://192.168.0.125:1804/oss/manage/media-library/result/bb0d27fa79724b5f96cbb03e80f679a0/tileset.json'}, //港湾一号
|
|
|
+ {fromCesium:1, url:'http://192.168.0.125:1804/oss/manage/media-library/result/0e68916bb02143a7afb9fed4561720a1/tileset.json'}, //ENU坐标 和地图对不上
|
|
|
//`${Potree.resourcePath}/models/3dtiles/test/tileset.json`,
|
|
|
//'http://192.168.0.25/oss/manage/media-library/result/test/tileset.json',
|
|
|
'https://4dkk.4dage.com/scene_view_data/SG-t-GvKLWIKfJGC/images/3dtiles/tileset.json?_=1742785956443',
|
|
|
@@ -401,13 +483,15 @@ var start = function(dom, mapDom, number, fileServer, webSite){ //t-Zvd3w0m
|
|
|
|
|
|
|
|
|
|
|
|
+ let lonlat = [83.0246,41.715012] /* 113.60,22.36 */
|
|
|
+ Potree.setLonlat(...lonlat)
|
|
|
+ initializeTransformation(lonlat)
|
|
|
|
|
|
- Potree.setLonlat(113.60,22.36)
|
|
|
-
|
|
|
+ createCesiumMap()
|
|
|
|
|
|
- let modelType, modelEditing, MergeEditor = viewer.modules.MergeEditor
|
|
|
+ let modelType, modelEditing
|
|
|
Potree.addModel = function(name, done, url, fixPose){
|
|
|
-
|
|
|
+ let fromCesium
|
|
|
cancelMove()
|
|
|
modelType = name
|
|
|
|
|
|
@@ -415,7 +499,7 @@ var start = function(dom, mapDom, number, fileServer, webSite){ //t-Zvd3w0m
|
|
|
MergeEditor.modelAdded(model)
|
|
|
if(!fixPose){
|
|
|
modelEditing = model;
|
|
|
- MergeEditor.setModelBtmHeight(model, 0) //默认离地高度为0
|
|
|
+
|
|
|
/* if(name == '3dTiles'){
|
|
|
setTimeout(()=>{
|
|
|
moveModel({pointer:{x:0,y:0}}) //3dTiles的移动会错乱,先默认放在当前视图中间吧
|
|
|
@@ -428,7 +512,23 @@ var start = function(dom, mapDom, number, fileServer, webSite){ //t-Zvd3w0m
|
|
|
//}
|
|
|
}else{
|
|
|
modelEditing = null
|
|
|
+
|
|
|
+ if(fromCesium){
|
|
|
+ let center = new THREE.Vector3().fromArray(model.runtime.getTileset().tileset.root.transform.slice(12,15))
|
|
|
+
|
|
|
+ let pos = Potree.math.fromCes(center)
|
|
|
+ model.position.copy(pos)
|
|
|
+ //viewer.modules.MergeEditor.moveBoundCenterTo( model, new THREE.Vector3().fromArray(pos) )
|
|
|
+ //因为bound中心在原点所以上面两句都可以
|
|
|
+
|
|
|
+ model.hasLonLat = true
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
}
|
|
|
+
|
|
|
+
|
|
|
{//transform
|
|
|
let updateBound = ()=>{
|
|
|
model.updateMatrixWorld()
|
|
|
@@ -457,7 +557,8 @@ var start = function(dom, mapDom, number, fileServer, webSite){ //t-Zvd3w0m
|
|
|
//model.updateMatrixWorld()
|
|
|
viewer.updateModelBound()
|
|
|
model.lastMatrixWorld = model.matrixWorld.clone();
|
|
|
- model.boundCenter || MergeEditor.getBoundCenter(model) //初始化
|
|
|
+ MergeEditor.setModelBtmHeight(model, 0) //默认离地高度为0
|
|
|
+ MergeEditor.getBoundCenter(model) //初始化
|
|
|
|
|
|
|
|
|
|
|
|
@@ -578,15 +679,21 @@ var start = function(dom, mapDom, number, fileServer, webSite){ //t-Zvd3w0m
|
|
|
}else if(name == '3dTiles'){
|
|
|
|
|
|
//------------
|
|
|
-
|
|
|
+ if(!url){
|
|
|
+ url = tilesetUrls[tileIndex++]
|
|
|
+ if(typeof(url) == 'object' ){
|
|
|
+ url.fromCesium && (fixPose = 1, fromCesium = 1)
|
|
|
+ url = url.url
|
|
|
+ }
|
|
|
+ }
|
|
|
viewer.loadModel({
|
|
|
fileType:'3dTiles',
|
|
|
- url: url || tilesetUrls[tileIndex++],
|
|
|
-
|
|
|
+ url,
|
|
|
transform : {
|
|
|
rotation : [0, 0, 0],
|
|
|
position : [0,0,0]
|
|
|
- }
|
|
|
+ },
|
|
|
+ side: fromCesium ? 1 : 0
|
|
|
},callback,onprogress)
|
|
|
|
|
|
|
|
|
@@ -814,20 +921,267 @@ var start = function(dom, mapDom, number, fileServer, webSite){ //t-Zvd3w0m
|
|
|
|
|
|
})
|
|
|
},2000) */
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ function createCesiumMap(){
|
|
|
+ //if(!browser.ur)
|
|
|
+ viewer.backgroundOpacity = 0
|
|
|
+ Cesium.Ion.defaultAccessToken = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiIxOGJlY2NkYy04NGZiLTQ2MzYtYWJmZi0xNzNlNDk0N2Q2YjAiLCJpZCI6MjUyOTI2LCJpYXQiOjE3MzA3ODY3MTN9.GiCzHsI5RCIWSPp5aiI7mvsu0emeCtjrTNOpwyIK7zw'
|
|
|
+
|
|
|
+ window.cesiumViewer = new Cesium.Viewer('potree_render_area', {
|
|
|
+ useDefaultRenderLoop: true,
|
|
|
+ requestRenderMode: true, //add 只有需要render时才会render,如tile加载完后、镜头移动后
|
|
|
+ animation: false,
|
|
|
+ baseLayerPicker: false,
|
|
|
+ fullscreenButton: false,
|
|
|
+ geocoder: false,
|
|
|
+ homeButton: false,
|
|
|
+ infoBox: false,
|
|
|
+ sceneModePicker: false,
|
|
|
+ selectionIndicator: false,
|
|
|
+ timeline: false,
|
|
|
+ navigationHelpButton: false,
|
|
|
+ //高德秘钥版 imageryProvider: new Cesium.AmapImageryProvider({key, mapStyle: 'normal'})
|
|
|
+ //报错 401 (Unauthorized) 的方法 https://blog.csdn.net/LBY_XK/article/details/121992641
|
|
|
+
|
|
|
+ //terrainShadows: Cesium.ShadowMode.DISABLED, //terrain地形 //自带的地图直接用84坐标
|
|
|
+ });
|
|
|
+ buildMapFromProp()
|
|
|
+ }
|
|
|
+
|
|
|
+ function buildMapFromProp(){
|
|
|
+ cesiumViewer.imageryLayers.removeAll();
|
|
|
+
|
|
|
+ defaultMapProps.forEach(e=>{
|
|
|
+ let gaoDeImageryProvider = new Cesium.UrlTemplateImageryProvider({
|
|
|
+ url:e.url,
|
|
|
+ minimumLevel: 0,
|
|
|
+ maximumLevel: e.maximumLevel,
|
|
|
+ credit: new Cesium.Credit(e.name),
|
|
|
+ tilingScheme: new AmapMercatorTilingScheme(), //修改投影,从84->高德
|
|
|
+ crossOrigin: 'anonymous',
|
|
|
+ })
|
|
|
+ cesiumViewer.imageryLayers.addImageryProvider(gaoDeImageryProvider);
|
|
|
+ })
|
|
|
+
|
|
|
+ updateMap()
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ function initializeTransformation([originLon,originLat]) {
|
|
|
+
|
|
|
+ const originHeight = 0;
|
|
|
+
|
|
|
+ let origin = Cesium.Cartesian3.fromDegrees(
|
|
|
+ originLon,
|
|
|
+ originLat,
|
|
|
+ originHeight
|
|
|
+ );
|
|
|
+
|
|
|
+ // 创建ENU到ECEF的转换矩阵
|
|
|
+ ecefToEnuMatrix = Cesium.Transforms.eastNorthUpToFixedFrame(
|
|
|
+ origin
|
|
|
+ );
|
|
|
+ /* enuToEcefMatrix = Cesium.Matrix4.inverse(
|
|
|
+ ecefToEnuMatrix,
|
|
|
+ new Cesium.Matrix4()
|
|
|
+ ); */
|
|
|
+ }
|
|
|
+
|
|
|
+ function updateMap(){
|
|
|
+
|
|
|
+ if (Potree.settings.showCesium && Potree.settings.displayMode == 'showPointCloud') {
|
|
|
+ let camera = MergeEditor.split ? viewer.viewports.find(e=>e.name == 'top').camera : viewer.mainViewport.camera
|
|
|
+ let pPos = new THREE.Vector3(0, 0, 0).applyMatrix4(camera.matrixWorld);
|
|
|
+
|
|
|
+ let orientation
|
|
|
+
|
|
|
+ let cPos = Potree.math.toCes(pPos);
|
|
|
+ //let pos2 = convertThreeToCesium(pPos)
|
|
|
+
|
|
|
+ if(MergeEditor.split){
|
|
|
+ pPos.y = 5408190 //为什么很高的时候会变位置,所以固定下
|
|
|
+ orientation = {
|
|
|
+ heading: Cesium.Math.toRadians(0.0), // 方向角
|
|
|
+ pitch: Cesium.Math.toRadians(-90.0), // 俯仰角
|
|
|
+ roll: 0.0 // 翻滚角
|
|
|
+ }
|
|
|
+
|
|
|
+ if(!cesiumViewer.camera.perpFrustum_){
|
|
|
+ cesiumViewer.camera.perpFrustum_ = cesiumViewer.camera.frustum
|
|
|
+ cesiumViewer.camera.frustum = new Cesium.OrthographicOffCenterFrustum({//OrthographicFrustum OrthographicOffCenterFrustum
|
|
|
+ left: -10000, // 左边界
|
|
|
+ right: 10000, // 右边界
|
|
|
+ bottom: -10000, // 下边界
|
|
|
+ top: 10000, // 上边界
|
|
|
+ near: 1.0, // 近裁剪面距离
|
|
|
+ far: 100000000.0, // 远裁剪面距离
|
|
|
+ })
|
|
|
+ }
|
|
|
+
|
|
|
+ cesiumViewer.camera.frustum.left = camera.left / camera.zoom
|
|
|
+ cesiumViewer.camera.frustum.right = camera.right / camera.zoom
|
|
|
+ cesiumViewer.camera.frustum.top = camera.top / camera.zoom
|
|
|
+ cesiumViewer.camera.frustum.bottom = camera.bottom / camera.zoom
|
|
|
+
|
|
|
+
|
|
|
+ }else{
|
|
|
+
|
|
|
+ cesiumViewer.camera.perpFrustum_ && (cesiumViewer.camera.frustum = cesiumViewer.camera.perpFrustum_, cesiumViewer.camera.perpFrustum_ = null) //恢复
|
|
|
+
|
|
|
+ //let pRight = new THREE.Vector3(600, 0, 0).applyMatrix4(camera.matrixWorld);
|
|
|
+ let pUp = new THREE.Vector3(0, 600, 0).applyMatrix4(camera.matrixWorld);
|
|
|
+ let pTarget = viewer.scene.view.getPivot();
|
|
|
+
|
|
|
+ let cUpTarget = Potree.math.toCes(pUp);
|
|
|
+ let cTarget = Potree.math.toCes(pTarget);
|
|
|
+
|
|
|
+ let cDir = Cesium.Cartesian3.subtract(cTarget, cPos, new Cesium.Cartesian3());
|
|
|
+ let cUp = Cesium.Cartesian3.subtract(cUpTarget, cPos, new Cesium.Cartesian3());
|
|
|
+
|
|
|
+ cDir = Cesium.Cartesian3.normalize(cDir, new Cesium.Cartesian3());
|
|
|
+ cUp = Cesium.Cartesian3.normalize(cUp, new Cesium.Cartesian3());
|
|
|
+ //console.log('ces', 'cPos', cPos, 'cDir',cDir, 'cUp', cUp)
|
|
|
+
|
|
|
+ //关键:计算始终朝北的向上向量
|
|
|
+ //cUp = computeNorthUpVector(pos2, cDir); //
|
|
|
+
|
|
|
+ orientation = {
|
|
|
+ direction: cDir,
|
|
|
+ up: cUp
|
|
|
+ }
|
|
|
+ let aspect = cesAspect || camera.aspect;
|
|
|
+ //console.log('updateMap', aspect)
|
|
|
+
|
|
|
+ if (aspect < 1) {
|
|
|
+ let fovy = Math.PI * (viewer.scene.getActiveCamera().fov / 180);
|
|
|
+ cesiumViewer.camera.frustum.fov = fovy;
|
|
|
+ } else {
|
|
|
+ let fovy = Math.PI * (viewer.scene.getActiveCamera().fov / 180);
|
|
|
+ let fovx = Math.atan(Math.tan(0.5 * fovy) * aspect) * 2
|
|
|
+ cesiumViewer.camera.frustum.fov = fovx;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ cesiumViewer.camera.setView({
|
|
|
+ destination: cPos,
|
|
|
+ orientation
|
|
|
+ });
|
|
|
+
|
|
|
+
|
|
|
+ cesiumViewer.scene.globe.show = camera.position.z > 0 //在地面之下地球会闪烁,故隐藏
|
|
|
+ cesiumViewer.render(); //立即render,否则会和点云render不同步而错位
|
|
|
+ }//cesium测试沙盒 https://sandcastle.cesium.com/
|
|
|
+ }
|
|
|
+
|
|
|
+ /*
|
|
|
+ function computeNorthUpVector(position,direction_){//计算始终指向地理北的向上向量
|
|
|
+ // 方法1:使用当前位置的ENU矩阵
|
|
|
+ const enuMatrix = Cesium.Transforms.eastNorthUpToFixedFrame(position);
|
|
|
+ const north = new Cesium.Cartesian3();
|
|
|
+
|
|
|
+ // 获取北方向(ENU矩阵的第二列)
|
|
|
+ Cesium.Matrix4.getColumn(enuMatrix, 1, north);
|
|
|
+ Cesium.Cartesian3.normalize(north, north);
|
|
|
+
|
|
|
+ // 获取天顶方向(第三列)
|
|
|
+ const up = new Cesium.Cartesian3();
|
|
|
+ Cesium.Matrix4.getColumn(enuMatrix, 2, up);
|
|
|
+ Cesium.Cartesian3.normalize(up, up);
|
|
|
+
|
|
|
+ // 根据相机俯仰角调整:如果相机看地平线,使用北方向;如果看天空,使用天顶方向
|
|
|
+ const direction = cesiumViewer.camera.direction;
|
|
|
+ if(isNaN(direction.x)){
|
|
|
+ direction.x = direction_.x
|
|
|
+ direction.y = direction_.y
|
|
|
+ direction.z = direction_.z
|
|
|
+ }
|
|
|
+
|
|
|
+ const pitchAngle = Math.acos(Cesium.Cartesian3.dot(direction, up));
|
|
|
+
|
|
|
+ // 如果相机接近垂直向下看,主要使用北方向保持文字朝北
|
|
|
+ if (pitchAngle < Math.PI / 6) { // 小于30度
|
|
|
+ return north;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 否则使用天顶方向,但要确保不失去北向参考
|
|
|
+ return adjustUpForNorthReference(up, north, direction);
|
|
|
+ }
|
|
|
+ // 调整向上向量以保持北向参考
|
|
|
+ function adjustUpForNorthReference(up, north, direction) {
|
|
|
+ // 确保向上向量与方向垂直
|
|
|
+ const adjustedUp = new Cesium.Cartesian3();
|
|
|
+
|
|
|
+ // 计算右侧向量
|
|
|
+ const right = Cesium.Cartesian3.cross(direction, up, new Cesium.Cartesian3());
|
|
|
+ Cesium.Cartesian3.normalize(right, right);
|
|
|
+
|
|
|
+ // 重新计算向上向量,使其垂直于方向和右侧
|
|
|
+ Cesium.Cartesian3.cross(right, direction, adjustedUp);
|
|
|
+ Cesium.Cartesian3.normalize(adjustedUp, adjustedUp);
|
|
|
+
|
|
|
+ // 投影北方向到垂直于方向的平面
|
|
|
+ const northProjected = projectVectorOntoPlane(north, direction);
|
|
|
+ Cesium.Cartesian3.normalize(northProjected, northProjected);
|
|
|
+
|
|
|
+ // 计算向上向量与北方向的夹角
|
|
|
+ const angle = Math.acos(Cesium.Cartesian3.dot(adjustedUp, northProjected));
|
|
|
+
|
|
|
+ // 如果夹角太大,稍微旋转向上向量使其更接近北方向
|
|
|
+ if (Math.abs(angle) > Math.PI / 4) { // 大于45度
|
|
|
+ const rotationAngle = -angle * 0.5; // 旋转一半的角度
|
|
|
+ const rotationMatrix = Cesium.Matrix3.fromRotationZ(rotationAngle);
|
|
|
+ Cesium.Matrix3.multiplyByVector(rotationMatrix, adjustedUp, adjustedUp);
|
|
|
+ }
|
|
|
+
|
|
|
+ return adjustedUp;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 向量投影到平面
|
|
|
+ function projectVectorOntoPlane(vector, planeNormal) {
|
|
|
+ const normal = Cesium.Cartesian3.normalize(planeNormal, new Cesium.Cartesian3());
|
|
|
+ const dot = Cesium.Cartesian3.dot(vector, normal);
|
|
|
+
|
|
|
+ const projected = new Cesium.Cartesian3();
|
|
|
+ Cesium.Cartesian3.multiplyByScalar(normal, dot, projected);
|
|
|
+ Cesium.Cartesian3.subtract(vector, projected, projected);
|
|
|
+
|
|
|
+ return projected;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 坐标转换:THREE局部坐标 → Cesium ECEF坐标
|
|
|
+ function convertThreeToCesium(threeVector) {
|
|
|
+ // THREE局部坐标(米)
|
|
|
+ const enuX = threeVector.x;
|
|
|
+ const enuY = threeVector.y;
|
|
|
+ const enuZ = threeVector.z;
|
|
|
+
|
|
|
+ // 创建ENU坐标的Cartesian3
|
|
|
+ const enuPosition = new Cesium.Cartesian3(enuY, enuX, enuZ); // 注意坐标轴对应关系
|
|
|
+
|
|
|
+ // 转换到ECEF
|
|
|
+ const ecefPosition = new Cesium.Cartesian3();
|
|
|
+ Cesium.Matrix4.multiplyByPoint(
|
|
|
+ ecefToEnuMatrix,
|
|
|
+ enuPosition,
|
|
|
+ ecefPosition
|
|
|
+ );
|
|
|
+
|
|
|
+ return ecefPosition;
|
|
|
+ }
|
|
|
+ */
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
|
|
|
|
|
|
|