右键改回 Cesium 原生 tilt,移除自定义环视逻辑
This commit is contained in:
+1
-172
@@ -26,11 +26,6 @@ const IMAGERY_URL =
|
|||||||
const TERRAIN_URL =
|
const TERRAIN_URL =
|
||||||
'https://elevation3d.arcgis.com/arcgis/rest/services/WorldElevation3D/Terrain3D/ImageServer';
|
'https://elevation3d.arcgis.com/arcgis/rest/services/WorldElevation3D/Terrain3D/ImageServer';
|
||||||
|
|
||||||
// 右键环视角度限制与灵敏度
|
|
||||||
const MAX_LOOK_ROT = (40 * Math.PI) / 180; // 左右旋转 ±40°
|
|
||||||
const MAX_LOOK_TILT = (20 * Math.PI) / 180; // 上下倾角 ±20°
|
|
||||||
const LOOK_RATE = Math.PI / 720; // 每像素约 0.25°
|
|
||||||
|
|
||||||
// 计算多边形集合的球面面积(km²),用于按国土面积分级国家名字号
|
// 计算多边形集合的球面面积(km²),用于按国土面积分级国家名字号
|
||||||
function sphericalAreaKm2(polys) {
|
function sphericalAreaKm2(polys) {
|
||||||
let area = 0;
|
let area = 0;
|
||||||
@@ -217,6 +212,7 @@ export class CesiumGlobe {
|
|||||||
Cesium.CameraEventType.PINCH,
|
Cesium.CameraEventType.PINCH,
|
||||||
];
|
];
|
||||||
controller.tiltEventTypes = [
|
controller.tiltEventTypes = [
|
||||||
|
Cesium.CameraEventType.RIGHT_DRAG, // 右键 = 原生 tilt(传统环视)
|
||||||
Cesium.CameraEventType.PINCH,
|
Cesium.CameraEventType.PINCH,
|
||||||
{
|
{
|
||||||
eventType: Cesium.CameraEventType.LEFT_DRAG,
|
eventType: Cesium.CameraEventType.LEFT_DRAG,
|
||||||
@@ -259,7 +255,6 @@ export class CesiumGlobe {
|
|||||||
|
|
||||||
this._buildMarkers();
|
this._buildMarkers();
|
||||||
this._setupPick();
|
this._setupPick();
|
||||||
this._setupLookAround();
|
|
||||||
this._loadBoundaries();
|
this._loadBoundaries();
|
||||||
this._buildCityLabels();
|
this._buildCityLabels();
|
||||||
|
|
||||||
@@ -360,172 +355,6 @@ export class CesiumGlobe {
|
|||||||
viewer.screenSpaceEventHandler.removeInputAction(Cesium.ScreenSpaceEventType.LEFT_DOUBLE_CLICK);
|
viewer.screenSpaceEventHandler.removeInputAction(Cesium.ScreenSpaceEventType.LEFT_DOUBLE_CLICK);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 右键环视:绕相机注视点(地形表面)做轨道倾倒。左右 = 经度方向、上下 = 纬度方向,强制北朝上。
|
|
||||||
// 关键:把轨道后的视线方向转到 ENU 后直接求 heading/pitch 传给 setView,
|
|
||||||
// 绕过 setView 在近天底处用 up 反推 heading 的奇点(否则小角度倾斜会被翻转)。
|
|
||||||
_setupLookAround() {
|
|
||||||
const scene = this.viewer.scene;
|
|
||||||
const camera = this.viewer.camera;
|
|
||||||
const handler = new Cesium.ScreenSpaceEventHandler(scene.canvas);
|
|
||||||
this._lookState = null;
|
|
||||||
this._orbitScratch = {
|
|
||||||
offset: new Cesium.Cartesian3(),
|
|
||||||
upAxis: new Cesium.Cartesian3(),
|
|
||||||
eastAxis: new Cesium.Cartesian3(),
|
|
||||||
northAxis: new Cesium.Cartesian3(),
|
|
||||||
qAz: new Cesium.Quaternion(),
|
|
||||||
qEl: new Cesium.Quaternion(),
|
|
||||||
q: new Cesium.Quaternion(),
|
|
||||||
rotMat: new Cesium.Matrix3(),
|
|
||||||
newOffset: new Cesium.Cartesian3(),
|
|
||||||
newPos: new Cesium.Cartesian3(),
|
|
||||||
dir: new Cesium.Cartesian3(),
|
|
||||||
enu: new Cesium.Matrix4(),
|
|
||||||
invEnu: new Cesium.Matrix4(),
|
|
||||||
localDir: new Cesium.Cartesian3(),
|
|
||||||
enuUp: new Cesium.Cartesian3(),
|
|
||||||
u0: new Cesium.Cartesian3(),
|
|
||||||
un: new Cesium.Cartesian3(),
|
|
||||||
cross: new Cesium.Cartesian3(),
|
|
||||||
};
|
|
||||||
|
|
||||||
handler.setInputAction((movement) => {
|
|
||||||
// 取消左键旋转/缩放/倾斜的惯性余力,避免右键拖动时叠加成“又转又倾斜”
|
|
||||||
const ctrl = scene.screenSpaceCameraController;
|
|
||||||
const inertiaStates = [
|
|
||||||
'_lastInertiaSpinMovement',
|
|
||||||
'_lastInertiaZoomMovement',
|
|
||||||
'_lastInertiaTiltMovement',
|
|
||||||
];
|
|
||||||
for (let i = 0; i < inertiaStates.length; i++) {
|
|
||||||
const st = ctrl[inertiaStates[i]];
|
|
||||||
if (st) st.inertiaEnabled = false;
|
|
||||||
}
|
|
||||||
// 旋转中心 = 相机当前注视的屏幕中心点(地形表面),而不是点击点
|
|
||||||
const canvas = scene.canvas;
|
|
||||||
const center = Cesium.Cartesian2.fromElements(
|
|
||||||
canvas.clientWidth / 2,
|
|
||||||
canvas.clientHeight / 2,
|
|
||||||
);
|
|
||||||
const ray = camera.getPickRay(center);
|
|
||||||
let pivot = scene.globe.pick(ray, scene);
|
|
||||||
if (!Cesium.defined(pivot)) {
|
|
||||||
pivot = camera.pickEllipsoid(center, scene.globe.ellipsoid);
|
|
||||||
}
|
|
||||||
if (!Cesium.defined(pivot)) return;
|
|
||||||
const sc = this._orbitScratch;
|
|
||||||
const offset = Cesium.Cartesian3.subtract(camera.position, pivot, sc.offset);
|
|
||||||
const upAxis = Cesium.Cartesian3.normalize(pivot, sc.upAxis);
|
|
||||||
const eastAxis = Cesium.Cartesian3.cross(Cesium.Cartesian3.UNIT_Z, pivot, sc.eastAxis); // 上下拖动(纬度方向)
|
|
||||||
if (Cesium.Cartesian3.magnitudeSquared(eastAxis) < 1e-12) {
|
|
||||||
eastAxis.x = 1;
|
|
||||||
eastAxis.y = 0;
|
|
||||||
eastAxis.z = 0; // 极点退化兜底
|
|
||||||
} else {
|
|
||||||
Cesium.Cartesian3.normalize(eastAxis, eastAxis);
|
|
||||||
}
|
|
||||||
const northAxis = Cesium.Cartesian3.normalize(
|
|
||||||
Cesium.Cartesian3.cross(upAxis, eastAxis, sc.northAxis), // 左右拖动(经度方向)
|
|
||||||
sc.northAxis,
|
|
||||||
);
|
|
||||||
this._lookState = {
|
|
||||||
pivot: Cesium.Cartesian3.clone(pivot),
|
|
||||||
startOffset: Cesium.Cartesian3.clone(offset),
|
|
||||||
eastAxis: Cesium.Cartesian3.clone(eastAxis),
|
|
||||||
northAxis: Cesium.Cartesian3.clone(northAxis),
|
|
||||||
position: Cesium.Cartesian3.clone(camera.position),
|
|
||||||
direction: Cesium.Cartesian3.clone(camera.direction),
|
|
||||||
up: Cesium.Cartesian3.clone(camera.up),
|
|
||||||
azimuth: 0,
|
|
||||||
elevation: 0,
|
|
||||||
lastX: movement.position.x,
|
|
||||||
lastY: movement.position.y,
|
|
||||||
};
|
|
||||||
}, Cesium.ScreenSpaceEventType.RIGHT_DOWN);
|
|
||||||
|
|
||||||
handler.setInputAction((movement) => {
|
|
||||||
if (!this._lookState) return;
|
|
||||||
const s = this._lookState;
|
|
||||||
const dx = movement.endPosition.x - s.lastX;
|
|
||||||
const dy = movement.endPosition.y - s.lastY;
|
|
||||||
s.lastX = movement.endPosition.x;
|
|
||||||
s.lastY = movement.endPosition.y;
|
|
||||||
s.azimuth = Cesium.Math.clamp(s.azimuth + dx * LOOK_RATE, -MAX_LOOK_ROT, MAX_LOOK_ROT);
|
|
||||||
s.elevation = Cesium.Math.clamp(s.elevation + dy * LOOK_RATE, -MAX_LOOK_TILT, MAX_LOOK_TILT);
|
|
||||||
this._orbitCamera(s);
|
|
||||||
}, Cesium.ScreenSpaceEventType.MOUSE_MOVE);
|
|
||||||
|
|
||||||
handler.setInputAction(() => {
|
|
||||||
if (!this._lookState) return;
|
|
||||||
const s = this._lookState;
|
|
||||||
this._lookState = null;
|
|
||||||
camera.setView({
|
|
||||||
destination: s.position,
|
|
||||||
orientation: { direction: s.direction, up: s.up },
|
|
||||||
});
|
|
||||||
}, Cesium.ScreenSpaceEventType.RIGHT_UP);
|
|
||||||
|
|
||||||
this._lookHandler = handler;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 轨道倾倒:左右绕南北轴、上下绕东西轴,位置沿轨道移动且始终看向注视点;直接算 heading/pitch 传 setView
|
|
||||||
_orbitCamera(s) {
|
|
||||||
const camera = this.viewer.camera;
|
|
||||||
const sc = this._orbitScratch;
|
|
||||||
Cesium.Quaternion.fromAxisAngle(s.northAxis, s.azimuth, sc.qAz);
|
|
||||||
Cesium.Quaternion.fromAxisAngle(s.eastAxis, s.elevation, sc.qEl);
|
|
||||||
Cesium.Quaternion.multiply(sc.qEl, sc.qAz, sc.q);
|
|
||||||
Cesium.Matrix3.fromQuaternion(sc.q, sc.rotMat);
|
|
||||||
Cesium.Matrix3.multiplyByVector(sc.rotMat, s.startOffset, sc.newOffset);
|
|
||||||
Cesium.Cartesian3.add(s.pivot, sc.newOffset, sc.newPos);
|
|
||||||
const dir = Cesium.Cartesian3.normalize(
|
|
||||||
Cesium.Cartesian3.subtract(s.pivot, sc.newPos, sc.dir),
|
|
||||||
sc.dir,
|
|
||||||
);
|
|
||||||
// 视线方向转到 newPos 处的 ENU,直接求 heading/pitch(避开 setView 近天底用 up 反推 heading 的翻转)
|
|
||||||
Cesium.Transforms.eastNorthUpToFixedFrame(
|
|
||||||
sc.newPos,
|
|
||||||
this.viewer.scene.globe.ellipsoid,
|
|
||||||
sc.enu,
|
|
||||||
);
|
|
||||||
Cesium.Matrix4.inverseTransformation(sc.enu, sc.invEnu);
|
|
||||||
Cesium.Matrix4.multiplyByPointAsVector(sc.invEnu, dir, sc.localDir);
|
|
||||||
const heading = Math.atan2(sc.localDir.x, sc.localDir.y);
|
|
||||||
const pitch = Math.asin(sc.localDir.z);
|
|
||||||
|
|
||||||
// 计算“北朝上”所需的 roll:把 roll=0 的 up(水平线方向)滚转到“世界 Z 投影”的 up,
|
|
||||||
// 这样倾斜时 up 不随方向转动(否则会又倾斜又旋转)
|
|
||||||
const dz = dir.z;
|
|
||||||
sc.un.x = -dir.x * dz;
|
|
||||||
sc.un.y = -dir.y * dz;
|
|
||||||
sc.un.z = 1 - dz * dz;
|
|
||||||
if (Cesium.Cartesian3.magnitudeSquared(sc.un) < 1e-12) {
|
|
||||||
Cesium.Cartesian3.clone(s.up, sc.un);
|
|
||||||
} else {
|
|
||||||
Cesium.Cartesian3.normalize(sc.un, sc.un);
|
|
||||||
}
|
|
||||||
Cesium.Cartesian3.normalize(sc.newPos, sc.enuUp); // 径向 = newPos 处的“上”
|
|
||||||
const d0 = Cesium.Cartesian3.dot(sc.enuUp, dir);
|
|
||||||
sc.u0.x = sc.enuUp.x - d0 * dir.x;
|
|
||||||
sc.u0.y = sc.enuUp.y - d0 * dir.y;
|
|
||||||
sc.u0.z = sc.enuUp.z - d0 * dir.z;
|
|
||||||
let roll = 0;
|
|
||||||
if (Cesium.Cartesian3.magnitudeSquared(sc.u0) > 1e-12) {
|
|
||||||
Cesium.Cartesian3.normalize(sc.u0, sc.u0);
|
|
||||||
Cesium.Cartesian3.cross(sc.u0, sc.un, sc.cross);
|
|
||||||
const sin =
|
|
||||||
Cesium.Cartesian3.magnitude(sc.cross) *
|
|
||||||
Math.sign(Cesium.Cartesian3.dot(sc.cross, dir));
|
|
||||||
const cos = Cesium.Cartesian3.dot(sc.u0, sc.un);
|
|
||||||
roll = Math.atan2(sin, cos);
|
|
||||||
}
|
|
||||||
|
|
||||||
camera.setView({
|
|
||||||
destination: Cesium.Cartesian3.clone(sc.newPos),
|
|
||||||
orientation: { heading, pitch, roll },
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// 相机平滑飞至某个标记上空并居中:回到与初始一致的高度与北朝上方向,左键拖拽手感不变
|
// 相机平滑飞至某个标记上空并居中:回到与初始一致的高度与北朝上方向,左键拖拽手感不变
|
||||||
flyToEntry(index) {
|
flyToEntry(index) {
|
||||||
const entry = ENTRIES[index];
|
const entry = ENTRIES[index];
|
||||||
|
|||||||
Reference in New Issue
Block a user