Files
td_official/src/views/equipment/index.js
2025-09-06 18:51:05 +08:00

393 lines
13 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

export class ModelPathMover {
/**
* 构造函数
* @param {Cesium.Viewer} viewer - Cesium viewer实例
* @param {Object} options - 配置选项
* @param {Number} [options.baseHeight=0] - 外部传入的统一高度(米),将叠加到所有位置点上
*/
constructor(viewer, options) {
this.viewer = viewer;
this.modelUrl = options.modelUrl;
this.positions = options.positions || [];
this.speed = options.speed || 10; // 米/秒
this.loop = options.loop !== undefined ? options.loop : true;
this.pathStyle = options.pathStyle || {
color: Cesium.Color.YELLOW,
width: 3
};
this.markerStyle = options.markerStyle || {
color: Cesium.Color.RED,
pixelSize: 10,
outlineColor: Cesium.Color.WHITE,
outlineWidth: 2
};
this.iconUrl = options.iconUrl;
this.iconSize = options.iconSize || 32;
this.iconOffset = options.iconOffset || 0;
this.headingOffset = options.headingOffset || 0;
// 新增接收外部传入的统一高度默认0米
this.baseHeight = options.baseHeight || 0;
// 内部状态(保持不变)
this.modelEntity = null;
this.pathEntity = null;
this.markerEntities = [];
this.iconEntity = null;
this.currentIndex = 0;
this.isMoving = false;
this.lastTime = 0;
this.animationFrameId = null;
this.currentPosition = null;
this.progress = 0;
this.modelHeight = 0;
// 初始化
this.init();
// 调试信息增加baseHeight打印
console.log('ModelPathMover初始化完成', {
positionCount: this.positions.length,
speed: this.speed,
loop: this.loop,
baseHeight: this.baseHeight // 打印传入的统一高度
});
}
/**
* 初始化(保持不变)
*/
init() {
if (this.positions.length < 2) {
console.warn('至少需要2个位置点才能进行移动');
}
this.createPath();
this.createMarkers();
this.createModel();
if (this.iconUrl) {
this.createIcon();
}
}
/**
* 创建模型修改叠加baseHeight
*/
createModel() {
if (this.positions.length === 0) return;
const firstPos = this.positions[0];
// 关键修改在原始高度基础上叠加baseHeight
const finalHeight = (firstPos.height || 0) + this.baseHeight;
this.currentPosition = Cesium.Cartesian3.fromDegrees(
firstPos.lon,
firstPos.lat,
finalHeight // 使用叠加后的高度
);
// 初始朝向计算(保持不变)
let initialOrientation = Cesium.Transforms.headingPitchRollQuaternion(this.currentPosition, new Cesium.HeadingPitchRoll(0, 0, 0));
if (this.positions.length > 1) {
const nextPos = this.positions[1];
// 计算下一个点时同样叠加baseHeight
const nextFinalHeight = (nextPos.height || 0) + this.baseHeight;
const nextCartesian = Cesium.Cartesian3.fromDegrees(nextPos.lon, nextPos.lat, nextFinalHeight);
const heading = this.calculateHeading(this.currentPosition, nextCartesian);
initialOrientation = Cesium.Transforms.headingPitchRollQuaternion(this.currentPosition, new Cesium.HeadingPitchRoll(heading, 0, 0));
}
this.modelEntity = this.viewer.entities.add({
name: 'Moving Model',
position: this.currentPosition,
orientation: initialOrientation,
model: {
uri: this.modelUrl,
minimumPixelSize: 64,
readyPromise: (model) => {
const boundingSphere = model.boundingSphere;
if (boundingSphere) {
this.modelHeight = boundingSphere.radius * 2;
console.log('模型高度检测完成:', this.modelHeight, '米');
}
}
}
});
}
/**
* 创建路径修改叠加baseHeight
*/
createPath() {
if (this.positions.length < 2) return;
// 关键修改遍历所有点时给每个点的高度叠加baseHeight
const pathPositions = this.positions.map((pos) => {
const finalHeight = (pos.height || 0) + this.baseHeight;
return Cesium.Cartesian3.fromDegrees(pos.lon, pos.lat, finalHeight);
});
this.pathEntity = this.viewer.entities.add({
name: 'Model Path',
polyline: {
positions: pathPositions,
width: this.pathStyle.width,
material: this.pathStyle.color,
clampToGround: false
}
});
}
/**
* 创建位置标记修改叠加baseHeight
*/
createMarkers() {
this.markerEntities = this.positions.map((pos, index) => {
// 关键修改标记点高度同样叠加baseHeight
const finalHeight = (pos.height || 0) + this.baseHeight;
const position = Cesium.Cartesian3.fromDegrees(pos.lon, pos.lat, finalHeight);
const marker = this.viewer.entities.add({
name: `Position Marker ${index}`,
position: position,
point: {
color: this.markerStyle.color,
pixelSize: this.markerStyle.pixelSize,
outlineColor: this.markerStyle.outlineColor,
outlineWidth: this.markerStyle.outlineWidth
},
label: {
text: pos.name || `Point ${index + 1}`,
font: '14px sans-serif',
pixelOffset: new Cesium.Cartesian2(0, -20),
fillColor: Cesium.Color.WHITE
}
});
return marker;
});
}
/**
* 创建模型上方的图标(保持不变)
*/
createIcon() {
this.iconEntity = this.viewer.entities.add({
name: 'Model Icon',
position: new Cesium.CallbackProperty(() => {
return this.adjustCartesianHeight(this.currentPosition, 0.3);
}, false),
billboard: {
image: this.iconUrl,
width: this.iconSize,
height: this.iconSize,
verticalOrigin: Cesium.VerticalOrigin.BOTTOM
},
label: {
text: 'Model Icon',
font: '14px sans-serif',
pixelOffset: new Cesium.Cartesian2(0, -40),
fillColor: Cesium.Color.WHITE
}
});
}
/**
* 调整笛卡尔坐标的高度(在原有高度基础上叠加指定值)
* @param {Cesium.Cartesian3} cartesian - 原始笛卡尔坐标
* @param {Number} heightOffset - 要增加的高度值(米,可为负数)
* @param {Cesium.Ellipsoid} [ellipsoid=Cesium.Ellipsoid.WGS84] - 参考椭球体
* @returns {Cesium.Cartesian3|null} 调整高度后的笛卡尔坐标失败返回null
*/
adjustCartesianHeight(cartesian, heightOffset, ellipsoid = Cesium.Ellipsoid.WGS84) {
// 1. 校验输入的笛卡尔坐标是否有效
// if (!Cesium.Cartesian3.isValid(cartesian)) {
// console.error("无效的笛卡尔坐标,无法调整高度");
// return null;
// }
// 2. 笛卡尔坐标 → Cartographic地理坐标含弧度经纬度和高度
const cartographic = Cesium.Cartographic.fromCartesian(cartesian, ellipsoid);
if (!cartographic) {
console.error('笛卡尔坐标转换为Cartographic失败');
return null;
}
// 3. 调整高度在原有高度上叠加offset可为负数
cartographic.height += heightOffset;
// 可选确保高度不低于0根据需求决定是否保留
// cartographic.height = Math.max(cartographic.height, 0);
// 4. Cartographic → 笛卡尔坐标(使用弧度经纬度转换)
const adjustedCartesian = Cesium.Cartesian3.fromRadians(
cartographic.longitude, // 经度(弧度)
cartographic.latitude, // 纬度(弧度)
cartographic.height, // 调整后的高度(米)
ellipsoid
);
return adjustedCartesian;
}
/**
* 开始移动(保持不变)
*/
start() {
if (this.isMoving) {
console.log('模型已经在移动中');
return;
}
if (this.positions.length < 2) {
console.error('无法移动位置点数量不足至少需要2个');
return;
}
this.isMoving = true;
this.lastTime = performance.now();
this.progress = 0;
console.log('开始移动,速度:', this.speed, '米/秒');
this.animate();
}
/**
* 动画循环函数(保持不变)
*/
animate() {
if (!this.isMoving) return;
const currentTime = performance.now();
const timeDeltaMs = currentTime - this.lastTime;
this.lastTime = currentTime;
const timeDelta = timeDeltaMs / 1000;
this.updatePosition(timeDelta);
this.animationFrameId = requestAnimationFrame(() => this.animate());
}
/**
* 停止移动(保持不变)
*/
stop() {
if (!this.isMoving) return;
this.isMoving = false;
console.log('停止移动');
if (this.animationFrameId) {
cancelAnimationFrame(this.animationFrameId);
this.animationFrameId = null;
}
}
/**
* 更新模型位置修改叠加baseHeight
*/
updatePosition(timeDelta) {
if (!this.isMoving) return;
const distanceToMove = this.speed * timeDelta;
const currentPos = this.positions[this.currentIndex];
const nextIndex = (this.currentIndex + 1) % this.positions.length;
const nextPos = this.positions[nextIndex];
// 关键修改计算当前点和下一点时均叠加baseHeight
const currentFinalHeight = (currentPos.height || 0) + this.baseHeight;
const nextFinalHeight = (nextPos.height || 0) + this.baseHeight;
const currentCartesian = Cesium.Cartesian3.fromDegrees(currentPos.lon, currentPos.lat, currentFinalHeight);
const nextCartesian = Cesium.Cartesian3.fromDegrees(nextPos.lon, nextPos.lat, nextFinalHeight);
// 后续逻辑保持不变
const totalDistance = Cesium.Cartesian3.distance(currentCartesian, nextCartesian);
if (totalDistance < 0.001) {
this.currentIndex = nextIndex;
this.progress = 0;
this.setModelPosition(nextCartesian, this.getNextPositionCartesian(nextIndex));
return;
}
this.progress += distanceToMove / totalDistance;
if (this.progress >= 1.0) {
const remainingDistance = (this.progress - 1.0) * totalDistance;
this.currentIndex = nextIndex;
if (!this.loop && this.currentIndex === this.positions.length - 1) {
this.setModelPosition(nextCartesian, null);
this.stop();
console.log('已到达终点,停止移动');
return;
}
const newTotalDistance = Cesium.Cartesian3.distance(nextCartesian, this.getNextPositionCartesian(this.currentIndex));
this.progress = newTotalDistance > 0.001 ? remainingDistance / newTotalDistance : 0;
this.setModelPosition(nextCartesian, this.getNextPositionCartesian(this.currentIndex));
} else {
const newPosition = Cesium.Cartesian3.lerp(currentCartesian, nextCartesian, this.progress, new Cesium.Cartesian3());
this.setModelPosition(newPosition, nextCartesian);
}
this.viewer.scene.requestRender();
}
/**
* 获取下一个位置的笛卡尔坐标修改叠加baseHeight
*/
getNextPositionCartesian(currentIndex) {
const nextIndex = (currentIndex + 1) % this.positions.length;
const nextPos = this.positions[nextIndex];
// 关键修改返回下一点时叠加baseHeight
const finalHeight = (nextPos.height || 0) + this.baseHeight;
return Cesium.Cartesian3.fromDegrees(nextPos.lon, nextPos.lat, finalHeight);
}
/**
* 设置模型位置和方向(保持不变)
*/
setModelPosition(position, targetPosition) {
if (!this.modelEntity) return;
this.currentPosition = position;
this.modelEntity.position.setValue(position);
if (targetPosition) {
const heading = this.calculateHeading(position, targetPosition);
this.modelEntity.orientation.setValue(Cesium.Transforms.headingPitchRollQuaternion(position, new Cesium.HeadingPitchRoll(heading, 0, 0)));
}
}
/**
* 计算两点之间的朝向(保持不变)
*/
calculateHeading(from, to) {
const fromCartographic = Cesium.Cartographic.fromCartesian(from);
const toCartographic = Cesium.Cartographic.fromCartesian(to);
const startLat = fromCartographic.latitude;
const startLon = fromCartographic.longitude;
const endLat = toCartographic.latitude;
const endLon = toCartographic.longitude;
const dLon = endLon - startLon;
const y = Math.sin(dLon) * Math.cos(endLat);
const x = Math.cos(startLat) * Math.sin(endLat) - Math.sin(startLat) * Math.cos(endLat) * Math.cos(dLon);
let heading = Math.atan2(y, x);
heading = (heading + Cesium.Math.TWO_PI) % Cesium.Math.TWO_PI;
heading = (heading + this.headingOffset) % Cesium.Math.TWO_PI;
return heading;
}
/**
* 手动设置模型高度(保持不变)
*/
setModelHeight(height) {
this.modelHeight = height;
console.log('手动设置模型高度:', height, '米');
}
/**
* 设置航向角偏移(保持不变)
*/
setHeadingOffset(offsetDegrees) {
this.headingOffset = Cesium.Math.toRadians(offsetDegrees);
console.log('设置航向角偏移:', offsetDegrees, '度');
}
/**
* 销毁所有资源(保持不变)
*/
destroy() {
this.stop();
if (this.modelEntity) this.viewer.entities.remove(this.modelEntity);
if (this.pathEntity) this.viewer.entities.remove(this.pathEntity);
this.markerEntities.forEach((marker) => this.viewer.entities.remove(marker));
if (this.iconEntity) this.viewer.entities.remove(this.iconEntity);
this.modelEntity = null;
this.pathEntity = null;
this.markerEntities = [];
this.iconEntity = null;
}
}