|
|
@@ -1,718 +1,372 @@
|
|
|
-// 模型编辑控制器
|
|
|
class ModelEditor {
|
|
|
constructor(viewer, entity) {
|
|
|
this.viewer = viewer;
|
|
|
this.entity = entity;
|
|
|
+
|
|
|
this.handler = null;
|
|
|
- this.activePrimitive = null;
|
|
|
- this.activeAxis = null;
|
|
|
- this.startMousePosition = null;
|
|
|
- this.startMouseCartesian = null;
|
|
|
- this.dragMode = null;
|
|
|
-
|
|
|
- this.translateEnabled = true;
|
|
|
- this.rotateEnabled = true;
|
|
|
- this.scaleEnabled = true;
|
|
|
-
|
|
|
- this.primitives = [];
|
|
|
- this.originPoint = null;
|
|
|
- this.moveAxes = [];
|
|
|
- this.axisPlanes = [];
|
|
|
- this.rotateAxes = [];
|
|
|
- this.scalePoints = [];
|
|
|
-
|
|
|
- // 获取 primitives 的辅助方法
|
|
|
- this.primitivesCollection = this.viewer.primitives || (this.viewer.scene && this.viewer.scene.primitives);
|
|
|
-
|
|
|
- this.center = this.getCenter();
|
|
|
- this.radius = this.getRadius();
|
|
|
-
|
|
|
- if (this.entity.model) {
|
|
|
- if (this.entity.model.readyPromise) {
|
|
|
- this.entity.model.readyPromise.then(() => {
|
|
|
- console.log('模型加载完成(通过 readyPromise)');
|
|
|
- this.center = this.getCenter();
|
|
|
- this.radius = this.getRadius();
|
|
|
- this.init();
|
|
|
- }).catch(() => {
|
|
|
- console.log('模型加载失败,使用当前位置初始化枢轴');
|
|
|
- this.center = this.getCenter();
|
|
|
- this.radius = this.getRadius();
|
|
|
- this.init();
|
|
|
- });
|
|
|
- } else if (this.entity.model.boundingSphere) {
|
|
|
- this.init();
|
|
|
- } else {
|
|
|
- console.log('模型没有 readyPromise,等待 boundingSphere');
|
|
|
- this.entity.model.definitionChanged.addEventListener(() => {
|
|
|
- if (this.entity.model.boundingSphere) {
|
|
|
- console.log('模型加载完成(通过 definitionChanged)');
|
|
|
- this.center = this.getCenter();
|
|
|
- this.radius = this.getRadius();
|
|
|
- this.init();
|
|
|
- }
|
|
|
- });
|
|
|
-
|
|
|
- setTimeout(() => {
|
|
|
- if (!this.entity.model.boundingSphere) {
|
|
|
- console.log('模型加载超时,使用当前位置初始化枢轴');
|
|
|
- this.center = this.getCenter();
|
|
|
- this.radius = this.getRadius();
|
|
|
- this.init();
|
|
|
- }
|
|
|
- }, 3000);
|
|
|
- }
|
|
|
- } else {
|
|
|
- this.init();
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- async waitForModelLoad() {
|
|
|
- if (this.initPromise) {
|
|
|
- await this.initPromise;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- getCenter() {
|
|
|
- // 首先尝试从 entity.position 获取中心点
|
|
|
- if (this.entity.position) {
|
|
|
- const position = this.entity.position.getValue(this.viewer.clock.currentTime);
|
|
|
- if (position) {
|
|
|
- return position;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- // 尝试多种方式获取模型中心点
|
|
|
- if (this.entity.model) {
|
|
|
- // 尝试直接访问 boundingSphere
|
|
|
- if (this.entity.model.boundingSphere) {
|
|
|
- return this.entity.model.boundingSphere.center;
|
|
|
- }
|
|
|
- // 尝试通过 _boundingSphere 访问
|
|
|
- if (this.entity.model._boundingSphere) {
|
|
|
- return this.entity.model._boundingSphere.center;
|
|
|
- }
|
|
|
- // 尝试通过 _primitive 访问
|
|
|
- if (this.entity.model._primitive && this.entity.model._primitive.boundingSphere) {
|
|
|
- return this.entity.model._primitive.boundingSphere.center;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- // 如果实体有 position 属性但没有获取到值,尝试获取实体的默认位置
|
|
|
- if (this.entity.position) {
|
|
|
- return this.entity.position.getValue(this.viewer.clock.currentTime) || this.viewer.camera.position;
|
|
|
- }
|
|
|
-
|
|
|
- // 返回相机位置作为默认值
|
|
|
- return this.viewer.camera.position;
|
|
|
- }
|
|
|
-
|
|
|
- getRadius() {
|
|
|
- // 首先尝试从模型获取半径
|
|
|
- if (this.entity.model) {
|
|
|
- // 尝试直接访问 boundingSphere
|
|
|
- if (this.entity.model.boundingSphere) {
|
|
|
- return this.entity.model.boundingSphere.radius;
|
|
|
- }
|
|
|
- // 尝试通过 _boundingSphere 访问
|
|
|
- if (this.entity.model._boundingSphere) {
|
|
|
- return this.entity.model._boundingSphere.radius;
|
|
|
- }
|
|
|
- // 尝试通过 _primitive 访问
|
|
|
- if (this.entity.model._primitive && this.entity.model._primitive.boundingSphere) {
|
|
|
- return this.entity.model._primitive.boundingSphere.radius;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- // 使用较小的默认半径
|
|
|
- return 2;
|
|
|
+ this.billboardCollection = null;
|
|
|
+ this.polylineCollection = null;
|
|
|
+
|
|
|
+ this.hoverBillboard = null;
|
|
|
+ this.isDragging = false;
|
|
|
+ this.dragType = null;
|
|
|
+ this.dragAxis = null;
|
|
|
+
|
|
|
+ this.startMousePos = null;
|
|
|
+ this.startScreenPos = null;
|
|
|
+ this.startWorldPos = null;
|
|
|
+ this.dragWorldAxis = null;
|
|
|
+ this.startModelMatrix = null;
|
|
|
+ this.startCenter = null;
|
|
|
+
|
|
|
+ this.center = null;
|
|
|
+ this.radius = 2;
|
|
|
+
|
|
|
+ this.init();
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
init() {
|
|
|
- // 先清理旧的 primitives
|
|
|
- this.clearPrimitives();
|
|
|
-
|
|
|
- this.handler = new Cesium.ScreenSpaceEventHandler(this.viewer.canvas);
|
|
|
- this.createPrimitives();
|
|
|
- this.addEventListener();
|
|
|
- }
|
|
|
-
|
|
|
- createPrimitives(isModel = true) {
|
|
|
- this.createOriginPoint();
|
|
|
-
|
|
|
- if (this.translateEnabled) {
|
|
|
- this.createMoveAxis();
|
|
|
- this.createAxisPlane();
|
|
|
- }
|
|
|
-
|
|
|
- if (isModel && this.rotateEnabled) {
|
|
|
- this.createRotateAxis();
|
|
|
- }
|
|
|
-
|
|
|
- if (isModel && this.scaleEnabled) {
|
|
|
- this.createScaleAxis();
|
|
|
- }
|
|
|
+ this.cleanup();
|
|
|
+ const scene = this.viewer.scene;
|
|
|
+ const canvas = scene.canvas;
|
|
|
+
|
|
|
+ this.handler = new Cesium.ScreenSpaceEventHandler(canvas);
|
|
|
+ this.billboardCollection = scene.primitives.add(new Cesium.BillboardCollection());
|
|
|
+ this.polylineCollection = scene.primitives.add(new Cesium.PolylineCollection());
|
|
|
+
|
|
|
+ this.center = this.entity.position.getValue(this.viewer.clock.currentTime);
|
|
|
+ this.createAllControls();
|
|
|
+ this.setupEvents();
|
|
|
}
|
|
|
-
|
|
|
- clearPrimitives() {
|
|
|
- this.primitives.forEach(p => {
|
|
|
- if (this.primitivesCollection) {
|
|
|
- this.primitivesCollection.remove(p);
|
|
|
+
|
|
|
+ createAllControls() {
|
|
|
+ const axisLength = this.radius * 0.8;
|
|
|
+ const rotateRadius = this.radius;
|
|
|
+ const axes = [
|
|
|
+ { key: 'X', color: Cesium.Color.RED, dir: new Cesium.Cartesian3(1, 0, 0) },
|
|
|
+ { key: 'Y', color: Cesium.Color.GREEN, dir: new Cesium.Cartesian3(0, 1, 0) },
|
|
|
+ { key: 'Z', color: Cesium.Color.BLUE, dir: new Cesium.Cartesian3(0, 0, 1) },
|
|
|
+ ];
|
|
|
+
|
|
|
+ // 平移轴
|
|
|
+ axes.forEach(({ key, color, dir }) => {
|
|
|
+ const end = this.localToWorld(new Cesium.Cartesian3(dir.x * axisLength, dir.y * axisLength, dir.z * axisLength));
|
|
|
+ this.billboardCollection.add({
|
|
|
+ position: end,
|
|
|
+ image: this.makeArrow(color),
|
|
|
+ disableDepthTestDistance: Number.POSITIVE_INFINITY,
|
|
|
+ id: { type: 'translate', axis: key }
|
|
|
+ });
|
|
|
+ this.polylineCollection.add({
|
|
|
+ positions: [this.center, end],
|
|
|
+ width: 3,
|
|
|
+ material: Cesium.Material.fromType('Color', { color })
|
|
|
+ });
|
|
|
+ });
|
|
|
+
|
|
|
+ // 旋转圆环
|
|
|
+ axes.forEach(({ key, color }) => {
|
|
|
+ const points = [];
|
|
|
+ for (let i = 0; i <= 64; i++) {
|
|
|
+ const ang = i / 64 * Math.PI * 2;
|
|
|
+ let p;
|
|
|
+ if (key === 'X') p = new Cesium.Cartesian3(0, Math.cos(ang) * rotateRadius, Math.sin(ang) * rotateRadius);
|
|
|
+ else if (key === 'Y') p = new Cesium.Cartesian3(Math.cos(ang) * rotateRadius, 0, Math.sin(ang) * rotateRadius);
|
|
|
+ else p = new Cesium.Cartesian3(Math.cos(ang) * rotateRadius, Math.sin(ang) * rotateRadius, 0);
|
|
|
+ points.push(this.localToWorld(p));
|
|
|
}
|
|
|
+ this.polylineCollection.add({
|
|
|
+ positions: points,
|
|
|
+ width: 2,
|
|
|
+ material: Cesium.Material.fromType('Color', { color })
|
|
|
+ });
|
|
|
+
|
|
|
+ let rotPos;
|
|
|
+ if (key === 'X') rotPos = this.localToWorld(new Cesium.Cartesian3(0, rotateRadius, 0));
|
|
|
+ else if (key === 'Y') rotPos = this.localToWorld(new Cesium.Cartesian3(rotateRadius, 0, 0));
|
|
|
+ else rotPos = this.localToWorld(new Cesium.Cartesian3(rotateRadius, 0, 0));
|
|
|
+
|
|
|
+ this.billboardCollection.add({
|
|
|
+ position: rotPos,
|
|
|
+ image: this.makeRing(color),
|
|
|
+ disableDepthTestDistance: Number.POSITIVE_INFINITY,
|
|
|
+ id: { type: 'rotate', axis: key }
|
|
|
+ });
|
|
|
+ });
|
|
|
+
|
|
|
+ // 缩放方块
|
|
|
+ axes.forEach(({ key, color, dir }) => {
|
|
|
+ const end = this.localToWorld(new Cesium.Cartesian3(dir.x * axisLength, dir.y * axisLength, dir.z * axisLength));
|
|
|
+ this.billboardCollection.add({
|
|
|
+ position: end,
|
|
|
+ image: this.makeBox(color),
|
|
|
+ disableDepthTestDistance: Number.POSITIVE_INFINITY,
|
|
|
+ id: { type: 'scale', axis: key }
|
|
|
+ });
|
|
|
});
|
|
|
- this.primitives = [];
|
|
|
- this.moveAxes = [];
|
|
|
- this.axisPlanes = [];
|
|
|
- this.rotateAxes = [];
|
|
|
- this.scalePoints = [];
|
|
|
- }
|
|
|
-
|
|
|
- createOriginPoint() {
|
|
|
- if (!this.center) return;
|
|
|
-
|
|
|
- const primitives = this.primitivesCollection;
|
|
|
- if (!primitives) return;
|
|
|
-
|
|
|
- const size = Math.max(this.radius * 0.05, 0.1);
|
|
|
-
|
|
|
- const primitive = primitives.add(new Cesium.Primitive({
|
|
|
- geometryInstances: new Cesium.GeometryInstance({
|
|
|
- geometry: new Cesium.BoxGeometry({
|
|
|
- vertexFormat: Cesium.VertexFormat.POSITION_AND_COLOR,
|
|
|
- maximum: new Cesium.Cartesian3(
|
|
|
- this.center.x + size,
|
|
|
- this.center.y + size,
|
|
|
- this.center.z + size
|
|
|
- ),
|
|
|
- minimum: new Cesium.Cartesian3(
|
|
|
- this.center.x - size,
|
|
|
- this.center.y - size,
|
|
|
- this.center.z - size
|
|
|
- )
|
|
|
- }),
|
|
|
- attributes: {
|
|
|
- color: Cesium.ColorGeometryInstanceAttribute.fromColor(Cesium.Color.WHITE.withAlpha(0.8))
|
|
|
- }
|
|
|
- }),
|
|
|
- appearance: new Cesium.PerInstanceColorAppearance({
|
|
|
- flat: true
|
|
|
- })
|
|
|
- }));
|
|
|
-
|
|
|
- this.primitives.push(primitive);
|
|
|
- this.originPoint = primitive;
|
|
|
}
|
|
|
-
|
|
|
- getModelRotationMatrix() {
|
|
|
- try {
|
|
|
- console.log('开始获取模型旋转矩阵');
|
|
|
- const entity = this.entity;
|
|
|
-
|
|
|
- if (entity.model) {
|
|
|
- const model = entity.model;
|
|
|
- console.log('model 属性:', Object.keys(model));
|
|
|
- console.log('model._nodeTransformations:', model._nodeTransformations);
|
|
|
-
|
|
|
- if (model._nodeTransformations) {
|
|
|
- console.log('遍历 nodeTransformations:');
|
|
|
- for (const key in model._nodeTransformations) {
|
|
|
- const node = model._nodeTransformations[key];
|
|
|
- console.log(' 节点:', key, node);
|
|
|
- if (node.rotation) {
|
|
|
- console.log(' rotation:', node.rotation);
|
|
|
- const rot = Cesium.Matrix3.fromQuaternion(node.rotation, new Cesium.Matrix3());
|
|
|
- console.log('从 nodeTransformations.rotation 获取旋转矩阵成功');
|
|
|
- return rot;
|
|
|
- }
|
|
|
- if (node.matrix) {
|
|
|
- console.log(' matrix:', node.matrix);
|
|
|
- const mat = new Cesium.Matrix4(
|
|
|
- node.matrix[0], node.matrix[1], node.matrix[2], node.matrix[3],
|
|
|
- node.matrix[4], node.matrix[5], node.matrix[6], node.matrix[7],
|
|
|
- node.matrix[8], node.matrix[9], node.matrix[10], node.matrix[11],
|
|
|
- node.matrix[12], node.matrix[13], node.matrix[14], node.matrix[15]
|
|
|
- );
|
|
|
- const rot = Cesium.Matrix4.getMatrix3(mat, new Cesium.Matrix3());
|
|
|
- console.log('从 nodeTransformations.matrix 获取旋转矩阵成功');
|
|
|
- return rot;
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- if (model._root) {
|
|
|
- console.log('model._root 存在');
|
|
|
- const root = model._root;
|
|
|
- console.log('root 属性:', Object.keys(root));
|
|
|
-
|
|
|
- if (root.transform) {
|
|
|
- console.log('root.transform:', root.transform);
|
|
|
- const rot = Cesium.Matrix4.getMatrix3(root.transform, new Cesium.Matrix3());
|
|
|
- console.log('从 root.transform 获取旋转矩阵成功');
|
|
|
- return rot;
|
|
|
- }
|
|
|
-
|
|
|
- if (root._transform) {
|
|
|
- console.log('root._transform:', root._transform);
|
|
|
- const rot = Cesium.Matrix4.getMatrix3(root._transform, new Cesium.Matrix3());
|
|
|
- console.log('从 root._transform 获取旋转矩阵成功');
|
|
|
- return rot;
|
|
|
- }
|
|
|
+
|
|
|
+ setupEvents() {
|
|
|
+ // 鼠标移动 - 悬停
|
|
|
+ this.handler.setInputAction((e) => {
|
|
|
+ if (this.isDragging) return;
|
|
|
+ const picked = this.pick(e.endPosition);
|
|
|
+
|
|
|
+ if (picked !== this.hoverBillboard) {
|
|
|
+ if (this.hoverBillboard) {
|
|
|
+ this.hoverBillboard.scale = 1.0;
|
|
|
+ this.hoverBillboard.color = Cesium.Color.WHITE;
|
|
|
}
|
|
|
- }
|
|
|
-
|
|
|
- console.log('无法获取旋转矩阵,使用单位矩阵');
|
|
|
- } catch (e) {
|
|
|
- console.log('获取旋转矩阵失败:', e);
|
|
|
- }
|
|
|
-
|
|
|
- return Cesium.Matrix3.IDENTITY.clone();
|
|
|
- }
|
|
|
-
|
|
|
- createMoveAxis() {
|
|
|
- if (!this.center) return;
|
|
|
-
|
|
|
- const length = this.radius * 0.8;
|
|
|
- const rotationMatrix = this.getModelRotationMatrix();
|
|
|
-
|
|
|
- const createAxis = (axis, color) => {
|
|
|
- let localOffset;
|
|
|
- if (axis === 'X') {
|
|
|
- localOffset = new Cesium.Cartesian3(length, 0, 0);
|
|
|
- } else if (axis === 'Y') {
|
|
|
- localOffset = new Cesium.Cartesian3(0, length, 0);
|
|
|
- } else {
|
|
|
- localOffset = new Cesium.Cartesian3(0, 0, length);
|
|
|
- }
|
|
|
-
|
|
|
- const worldOffset = Cesium.Matrix3.multiplyByVector(rotationMatrix, localOffset, new Cesium.Cartesian3());
|
|
|
-
|
|
|
- const points = [
|
|
|
- new Cesium.Cartesian3(this.center.x, this.center.y, this.center.z),
|
|
|
- new Cesium.Cartesian3(
|
|
|
- this.center.x + worldOffset.x,
|
|
|
- this.center.y + worldOffset.y,
|
|
|
- this.center.z + worldOffset.z
|
|
|
- )
|
|
|
- ];
|
|
|
-
|
|
|
- const primitive = this.primitivesCollection.add(new Cesium.Primitive({
|
|
|
- geometryInstances: new Cesium.GeometryInstance({
|
|
|
- geometry: new Cesium.PolylineGeometry({
|
|
|
- positions: points,
|
|
|
- vertexFormat: Cesium.VertexFormat.POSITION_AND_COLOR
|
|
|
- }),
|
|
|
- attributes: {
|
|
|
- color: Cesium.ColorGeometryInstanceAttribute.fromColor(color)
|
|
|
- }
|
|
|
- }),
|
|
|
- appearance: new Cesium.PolylineColorAppearance()
|
|
|
- }));
|
|
|
-
|
|
|
- this.primitives.push(primitive);
|
|
|
- this.moveAxes.push({ primitive, axis, color });
|
|
|
- return primitive;
|
|
|
- };
|
|
|
-
|
|
|
- createAxis('X', Cesium.Color.RED);
|
|
|
- createAxis('Y', Cesium.Color.GREEN);
|
|
|
- createAxis('Z', Cesium.Color.BLUE);
|
|
|
- }
|
|
|
-
|
|
|
- createAxisPlane() {
|
|
|
- if (!this.center) return;
|
|
|
-
|
|
|
- const size = this.radius * 0.8;
|
|
|
- const halfSize = size / 2;
|
|
|
-
|
|
|
- const createPlane = (axis1, axis2, color) => {
|
|
|
- let points = [];
|
|
|
-
|
|
|
- if (axis1 === 'X' && axis2 === 'Y') {
|
|
|
- points = [
|
|
|
- new Cesium.Cartesian3(-halfSize, -halfSize, 0),
|
|
|
- new Cesium.Cartesian3(halfSize, -halfSize, 0),
|
|
|
- new Cesium.Cartesian3(halfSize, halfSize, 0),
|
|
|
- new Cesium.Cartesian3(-halfSize, halfSize, 0)
|
|
|
- ];
|
|
|
- } else if (axis1 === 'X' && axis2 === 'Z') {
|
|
|
- points = [
|
|
|
- new Cesium.Cartesian3(-halfSize, 0, -halfSize),
|
|
|
- new Cesium.Cartesian3(halfSize, 0, -halfSize),
|
|
|
- new Cesium.Cartesian3(halfSize, 0, halfSize),
|
|
|
- new Cesium.Cartesian3(-halfSize, 0, halfSize)
|
|
|
- ];
|
|
|
- } else if (axis1 === 'Y' && axis2 === 'Z') {
|
|
|
- points = [
|
|
|
- new Cesium.Cartesian3(0, -halfSize, -halfSize),
|
|
|
- new Cesium.Cartesian3(0, halfSize, -halfSize),
|
|
|
- new Cesium.Cartesian3(0, halfSize, halfSize),
|
|
|
- new Cesium.Cartesian3(0, -halfSize, halfSize)
|
|
|
- ];
|
|
|
- }
|
|
|
-
|
|
|
- points = points.map(p => new Cesium.Cartesian3(
|
|
|
- this.center.x + p.x,
|
|
|
- this.center.y + p.y,
|
|
|
- this.center.z + p.z
|
|
|
- ));
|
|
|
-
|
|
|
- const primitive = this.primitivesCollection.add(new Cesium.Primitive({
|
|
|
- geometryInstances: new Cesium.GeometryInstance({
|
|
|
- geometry: new Cesium.PolygonGeometry({
|
|
|
- polygonHierarchy: new Cesium.PolygonHierarchy(points),
|
|
|
- extrudedHeight: 0.1
|
|
|
- }),
|
|
|
- attributes: {
|
|
|
- color: Cesium.ColorGeometryInstanceAttribute.fromColor(color.withAlpha(0.3))
|
|
|
- }
|
|
|
- }),
|
|
|
- appearance: new Cesium.PerInstanceColorAppearance({
|
|
|
- flat: true
|
|
|
- })
|
|
|
- }));
|
|
|
-
|
|
|
- this.primitives.push(primitive);
|
|
|
- this.axisPlanes.push({ primitive, axis1, axis2, color });
|
|
|
- };
|
|
|
-
|
|
|
- createPlane('X', 'Y', Cesium.Color.fromCssColorString('#ffff00'));
|
|
|
- createPlane('X', 'Z', Cesium.Color.fromCssColorString('#ff00ff'));
|
|
|
- createPlane('Y', 'Z', Cesium.Color.fromCssColorString('#00ffff'));
|
|
|
- }
|
|
|
-
|
|
|
- createRotateAxis() {
|
|
|
- if (!this.center) return;
|
|
|
-
|
|
|
- const ringRadius = this.radius * 1.0;
|
|
|
- const rotationMatrix = this.getModelRotationMatrix();
|
|
|
-
|
|
|
- const createRotateAxis = (axis, color) => {
|
|
|
- const points = [];
|
|
|
- const segments = 64;
|
|
|
-
|
|
|
- for (let i = 0; i <= segments; i++) {
|
|
|
- const angle = (i / segments) * Math.PI * 2;
|
|
|
- let localX, localY, localZ;
|
|
|
-
|
|
|
- if (axis === 'X') {
|
|
|
- localX = 0;
|
|
|
- localY = Math.cos(angle) * ringRadius;
|
|
|
- localZ = Math.sin(angle) * ringRadius;
|
|
|
- } else if (axis === 'Y') {
|
|
|
- localX = Math.cos(angle) * ringRadius;
|
|
|
- localY = 0;
|
|
|
- localZ = Math.sin(angle) * ringRadius;
|
|
|
- } else {
|
|
|
- localX = Math.cos(angle) * ringRadius;
|
|
|
- localY = Math.sin(angle) * ringRadius;
|
|
|
- localZ = 0;
|
|
|
+ this.hoverBillboard = picked;
|
|
|
+ if (this.hoverBillboard) {
|
|
|
+ this.hoverBillboard.scale = 1.5;
|
|
|
+ this.hoverBillboard.color = Cesium.Color.YELLOW;
|
|
|
}
|
|
|
-
|
|
|
- const worldOffset = Cesium.Matrix3.multiplyByVector(
|
|
|
- rotationMatrix,
|
|
|
- new Cesium.Cartesian3(localX, localY, localZ),
|
|
|
- new Cesium.Cartesian3()
|
|
|
- );
|
|
|
-
|
|
|
- points.push(new Cesium.Cartesian3(
|
|
|
- this.center.x + worldOffset.x,
|
|
|
- this.center.y + worldOffset.y,
|
|
|
- this.center.z + worldOffset.z
|
|
|
- ));
|
|
|
}
|
|
|
+ this.viewer.canvas.style.cursor = picked ? 'pointer' : 'default';
|
|
|
+ }, Cesium.ScreenSpaceEventType.MOUSE_MOVE);
|
|
|
+
|
|
|
+ // 左键按下
|
|
|
+ this.handler.setInputAction((e) => {
|
|
|
+ const bb = this.pick(e.position);
|
|
|
+ if (!bb) return;
|
|
|
+
|
|
|
+ this.isDragging = true;
|
|
|
+ this.dragType = bb.id.type;
|
|
|
+ this.dragAxis = bb.id.axis;
|
|
|
+ this.startMousePos = { x: e.position.x, y: e.position.y };
|
|
|
+ this.startScreenPos = { x: e.position.x, y: e.position.y };
|
|
|
|
|
|
- const primitive = this.primitivesCollection.add(new Cesium.Primitive({
|
|
|
- geometryInstances: new Cesium.GeometryInstance({
|
|
|
- geometry: new Cesium.PolylineGeometry({
|
|
|
- positions: points,
|
|
|
- vertexFormat: Cesium.VertexFormat.POSITION_AND_COLOR
|
|
|
- }),
|
|
|
- attributes: {
|
|
|
- color: Cesium.ColorGeometryInstanceAttribute.fromColor(color)
|
|
|
- }
|
|
|
- }),
|
|
|
- appearance: new Cesium.PolylineColorAppearance()
|
|
|
- }));
|
|
|
+ const localAxis = this.getAxis(this.dragAxis);
|
|
|
+ this.dragWorldAxis = this.localToWorld(localAxis);
|
|
|
+ Cesium.Cartesian3.normalize(this.dragWorldAxis, this.dragWorldAxis);
|
|
|
|
|
|
- this.primitives.push(primitive);
|
|
|
- this.rotateAxes.push({ primitive, axis, color });
|
|
|
- return primitive;
|
|
|
- };
|
|
|
-
|
|
|
- createRotateAxis('X', Cesium.Color.RED);
|
|
|
- createRotateAxis('Y', Cesium.Color.GREEN);
|
|
|
- createRotateAxis('Z', Cesium.Color.BLUE);
|
|
|
- }
|
|
|
-
|
|
|
- createScaleAxis() {
|
|
|
- if (!this.center) return;
|
|
|
-
|
|
|
- const length = this.radius * 0.8;
|
|
|
- const rotationMatrix = this.getModelRotationMatrix();
|
|
|
-
|
|
|
- const createScalePoint = (axis, color) => {
|
|
|
- let localOffset;
|
|
|
- if (axis === 'X') {
|
|
|
- localOffset = new Cesium.Cartesian3(length, 0, 0);
|
|
|
- } else if (axis === 'Y') {
|
|
|
- localOffset = new Cesium.Cartesian3(0, length, 0);
|
|
|
+ this.startCenter = this.entity.position.getValue ? this.entity.position.getValue(this.viewer.clock.currentTime) : this.entity.position;
|
|
|
+ this.center = Cesium.Cartesian3.clone(this.startCenter);
|
|
|
+
|
|
|
+ if (this.entity.model) {
|
|
|
+ this.startModelMatrix = Cesium.Matrix4.clone(this.entity.model.modelMatrix);
|
|
|
} else {
|
|
|
- localOffset = new Cesium.Cartesian3(0, 0, length);
|
|
|
- }
|
|
|
-
|
|
|
- const worldOffset = Cesium.Matrix3.multiplyByVector(rotationMatrix, localOffset, new Cesium.Cartesian3());
|
|
|
- const size = Math.max(this.radius * 0.08, 0.15);
|
|
|
-
|
|
|
- const primitive = this.primitivesCollection.add(new Cesium.Primitive({
|
|
|
- geometryInstances: new Cesium.GeometryInstance({
|
|
|
- geometry: new Cesium.BoxGeometry({
|
|
|
- vertexFormat: Cesium.VertexFormat.POSITION_AND_COLOR,
|
|
|
- maximum: new Cesium.Cartesian3(
|
|
|
- this.center.x + worldOffset.x + size,
|
|
|
- this.center.y + worldOffset.y + size,
|
|
|
- this.center.z + worldOffset.z + size
|
|
|
- ),
|
|
|
- minimum: new Cesium.Cartesian3(
|
|
|
- this.center.x + worldOffset.x - size,
|
|
|
- this.center.y + worldOffset.y - size,
|
|
|
- this.center.z + worldOffset.z - size
|
|
|
- )
|
|
|
- }),
|
|
|
- attributes: {
|
|
|
- color: Cesium.ColorGeometryInstanceAttribute.fromColor(color)
|
|
|
- }
|
|
|
- }),
|
|
|
- appearance: new Cesium.PerInstanceColorAppearance({
|
|
|
- flat: true
|
|
|
- })
|
|
|
- }));
|
|
|
-
|
|
|
- this.primitives.push(primitive);
|
|
|
- this.scalePoints.push({ primitive, axis, color });
|
|
|
- return primitive;
|
|
|
- };
|
|
|
-
|
|
|
- createScalePoint('X', Cesium.Color.RED);
|
|
|
- createScalePoint('Y', Cesium.Color.GREEN);
|
|
|
- createScalePoint('Z', Cesium.Color.BLUE);
|
|
|
- }
|
|
|
-
|
|
|
- addEventListener() {
|
|
|
- const handler = this.handler;
|
|
|
-
|
|
|
- handler.setInputAction((event) => {
|
|
|
- const picked = this.viewer.scene.pick(event.position);
|
|
|
-
|
|
|
- if (Cesium.defined(picked) && Cesium.defined(picked.primitive)) {
|
|
|
- this.activePrimitive = picked.primitive;
|
|
|
- this.startMousePosition = event.position;
|
|
|
-
|
|
|
- if (this.originPoint === picked.primitive) {
|
|
|
- this.dragMode = 'translate';
|
|
|
- this.activeAxis = 'XYZ';
|
|
|
- } else if (this.moveAxes.some(a => a.primitive === picked.primitive)) {
|
|
|
- const axisInfo = this.moveAxes.find(a => a.primitive === picked.primitive);
|
|
|
- this.dragMode = 'translate';
|
|
|
- this.activeAxis = axisInfo.axis;
|
|
|
- } else if (this.axisPlanes.some(p => p.primitive === picked.primitive)) {
|
|
|
- const planeInfo = this.axisPlanes.find(p => p.primitive === picked.primitive);
|
|
|
- this.dragMode = 'translate';
|
|
|
- this.activeAxis = planeInfo.axis1 + planeInfo.axis2;
|
|
|
- } else if (this.rotateAxes.some(r => r.primitive === picked.primitive)) {
|
|
|
- const axisInfo = this.rotateAxes.find(r => r.primitive === picked.primitive);
|
|
|
- this.dragMode = 'rotate';
|
|
|
- this.activeAxis = axisInfo.axis;
|
|
|
- } else if (this.scalePoints.some(s => s.primitive === picked.primitive)) {
|
|
|
- const axisInfo = this.scalePoints.find(s => s.primitive === picked.primitive);
|
|
|
- this.dragMode = 'scale';
|
|
|
- this.activeAxis = axisInfo.axis;
|
|
|
- }
|
|
|
-
|
|
|
- if (this.dragMode) {
|
|
|
- this.startMouseCartesian = this.pickCartesianFromMouse(event.position);
|
|
|
- }
|
|
|
+ this.startModelMatrix = Cesium.Matrix4.IDENTITY.clone();
|
|
|
}
|
|
|
+
|
|
|
+ this.viewer.scene.screenSpaceCameraController.enableInputs = false;
|
|
|
}, Cesium.ScreenSpaceEventType.LEFT_DOWN);
|
|
|
-
|
|
|
- handler.setInputAction((event) => {
|
|
|
- if (!this.dragMode || !this.activePrimitive) return;
|
|
|
-
|
|
|
- const currentMouseCartesian = this.pickCartesianFromMouse(event.position);
|
|
|
+
|
|
|
+ // 拖拽
|
|
|
+ this.handler.setInputAction((e) => {
|
|
|
+ if (!this.isDragging || !this.startScreenPos) return;
|
|
|
|
|
|
- if (!this.startMouseCartesian || !currentMouseCartesian) return;
|
|
|
+ const dx = e.endPosition.x - this.startScreenPos.x;
|
|
|
+ const dy = e.endPosition.y - this.startScreenPos.y;
|
|
|
|
|
|
- if (this.dragMode === 'translate') {
|
|
|
- this.translate(currentMouseCartesian);
|
|
|
- } else if (this.dragMode === 'rotate') {
|
|
|
- this.rotate(event.position);
|
|
|
- } else if (this.dragMode === 'scale') {
|
|
|
- this.scale(currentMouseCartesian);
|
|
|
+ if (this.dragType === 'rotate') {
|
|
|
+ const rotateDx = e.endPosition.x - this.startMousePos.x;
|
|
|
+ this.doRotate(rotateDx);
|
|
|
+ this.startMousePos = { x: e.endPosition.x, y: e.endPosition.y };
|
|
|
+ } else {
|
|
|
+ this.startScreenPos = { x: e.endPosition.x, y: e.endPosition.y };
|
|
|
+ if (this.dragType === 'translate') this.doTranslate(dx, dy);
|
|
|
+ if (this.dragType === 'scale') this.doScale(dx, dy);
|
|
|
}
|
|
|
-
|
|
|
- this.startMouseCartesian = currentMouseCartesian;
|
|
|
}, Cesium.ScreenSpaceEventType.MOUSE_MOVE);
|
|
|
-
|
|
|
- handler.setInputAction(() => {
|
|
|
- this.activePrimitive = null;
|
|
|
- this.dragMode = null;
|
|
|
- this.startMousePosition = null;
|
|
|
- this.startMouseCartesian = null;
|
|
|
+
|
|
|
+ // 左键抬起
|
|
|
+ this.handler.setInputAction(() => {
|
|
|
+ this.isDragging = false;
|
|
|
+ this.dragType = null;
|
|
|
+ this.startScreenPos = null;
|
|
|
+ this.dragWorldAxis = null;
|
|
|
+ this.viewer.scene.screenSpaceCameraController.enableInputs = true;
|
|
|
}, Cesium.ScreenSpaceEventType.LEFT_UP);
|
|
|
}
|
|
|
-
|
|
|
- pickCartesianFromMouse(mousePosition) {
|
|
|
- const ray = this.viewer.camera.getRay(mousePosition);
|
|
|
- const cartesian = this.viewer.scene.globe.pick(ray, this.viewer.scene);
|
|
|
-
|
|
|
- if (!cartesian) {
|
|
|
- // 如果没有与地面相交,则使用相机前方一定距离的点
|
|
|
- const position = this.viewer.camera.position;
|
|
|
- const direction = this.viewer.camera.direction;
|
|
|
- const distance = 100;
|
|
|
- cartesian = new Cesium.Cartesian3(
|
|
|
- position.x + direction.x * distance,
|
|
|
- position.y + direction.y * distance,
|
|
|
- position.z + direction.z * distance
|
|
|
- );
|
|
|
+
|
|
|
+ // 平移
|
|
|
+ doTranslate(dx, dy) {
|
|
|
+ const camera = this.viewer.camera;
|
|
|
+ const center = this.entity.position.getValue ? this.entity.position.getValue(this.viewer.clock.currentTime) : this.entity.position;
|
|
|
+ const dist = Cesium.Cartesian3.distance(camera.position, center);
|
|
|
+ const sensitivity = dist * 0.002;
|
|
|
+
|
|
|
+ const right = camera.right;
|
|
|
+ const up = camera.up;
|
|
|
+
|
|
|
+ const mat = Cesium.Transforms.eastNorthUpToFixedFrame(center);
|
|
|
+ const xAxis = Cesium.Matrix4.multiplyByPoint(mat, new Cesium.Cartesian3(1, 0, 0), new Cesium.Cartesian3());
|
|
|
+ const yAxis = Cesium.Matrix4.multiplyByPoint(mat, new Cesium.Cartesian3(0, 1, 0), new Cesium.Cartesian3());
|
|
|
+ const zAxis = Cesium.Matrix4.multiplyByPoint(mat, new Cesium.Cartesian3(0, 0, 1), new Cesium.Cartesian3());
|
|
|
+ Cesium.Cartesian3.subtract(xAxis, center, xAxis);
|
|
|
+ Cesium.Cartesian3.subtract(yAxis, center, yAxis);
|
|
|
+ Cesium.Cartesian3.subtract(zAxis, center, zAxis);
|
|
|
+
|
|
|
+ let moveDir;
|
|
|
+ if (this.dragAxis === 'X') {
|
|
|
+ moveDir = xAxis;
|
|
|
+ } else if (this.dragAxis === 'Y') {
|
|
|
+ moveDir = yAxis;
|
|
|
+ } else {
|
|
|
+ moveDir = zAxis;
|
|
|
}
|
|
|
+ Cesium.Cartesian3.normalize(moveDir, moveDir);
|
|
|
|
|
|
- return cartesian;
|
|
|
- }
|
|
|
-
|
|
|
- translate(currentMouseCartesian) {
|
|
|
- if (!this.startMouseCartesian || !currentMouseCartesian) return;
|
|
|
-
|
|
|
- const offset = new Cesium.Cartesian3(
|
|
|
- currentMouseCartesian.x - this.startMouseCartesian.x,
|
|
|
- currentMouseCartesian.y - this.startMouseCartesian.y,
|
|
|
- currentMouseCartesian.z - this.startMouseCartesian.z
|
|
|
- );
|
|
|
-
|
|
|
- // 根据选中轴过滤偏移量
|
|
|
- if (this.activeAxis.indexOf('X') === -1) offset.x = 0;
|
|
|
- if (this.activeAxis.indexOf('Y') === -1) offset.y = 0;
|
|
|
- if (this.activeAxis.indexOf('Z') === -1) offset.z = 0;
|
|
|
+ const screenDirX = right.x * dx + up.x * (-dy);
|
|
|
+ const screenDirY = right.y * dx + up.y * (-dy);
|
|
|
+ const screenDirZ = right.z * dx + up.z * (-dy);
|
|
|
+ const screenMove = new Cesium.Cartesian3(screenDirX, screenDirY, screenDirZ);
|
|
|
+ const dot = Cesium.Cartesian3.dot(screenMove, moveDir);
|
|
|
|
|
|
- // 更新实体位置
|
|
|
- if (this.entity.position) {
|
|
|
- const currentPosition = this.entity.position.getValue(this.viewer.clock.currentTime);
|
|
|
- if (currentPosition) {
|
|
|
- const newPosition = new Cesium.Cartesian3(
|
|
|
- currentPosition.x + offset.x,
|
|
|
- currentPosition.y + offset.y,
|
|
|
- currentPosition.z + offset.z
|
|
|
- );
|
|
|
- this.entity.position = newPosition;
|
|
|
- }
|
|
|
- }
|
|
|
+ const moveAmount = dot * sensitivity;
|
|
|
+ const offset = Cesium.Cartesian3.multiplyByScalar(moveDir, moveAmount, new Cesium.Cartesian3());
|
|
|
|
|
|
- // 更新中心点
|
|
|
- this.center = this.getCenter();
|
|
|
+ this.center = Cesium.Cartesian3.add(this.startCenter, offset, new Cesium.Cartesian3());
|
|
|
+ this.entity.position = Cesium.Cartesian3.clone(this.center);
|
|
|
+ this.startCenter = Cesium.Cartesian3.clone(this.center);
|
|
|
|
|
|
- // 重新创建枢轴
|
|
|
- this.init();
|
|
|
+ this.updateControls();
|
|
|
+ this.viewer.scene.requestRender();
|
|
|
}
|
|
|
|
|
|
- rotate(mousePosition) {
|
|
|
- if (!this.startMousePosition || !mousePosition) return;
|
|
|
-
|
|
|
- const deltaX = mousePosition.x - this.startMousePosition.x;
|
|
|
- const angle = deltaX * 0.01;
|
|
|
-
|
|
|
- let axis = new Cesium.Cartesian3(0, 0, 1);
|
|
|
- if (this.activeAxis === 'X') {
|
|
|
- axis = new Cesium.Cartesian3(1, 0, 0);
|
|
|
- } else if (this.activeAxis === 'Y') {
|
|
|
- axis = new Cesium.Cartesian3(0, 1, 0);
|
|
|
- } else if (this.activeAxis === 'Z') {
|
|
|
- axis = new Cesium.Cartesian3(0, 0, 1);
|
|
|
+ updateControls() {
|
|
|
+ if (this.billboardCollection) {
|
|
|
+ this.viewer.scene.primitives.remove(this.billboardCollection);
|
|
|
+ this.viewer.scene.primitives.remove(this.polylineCollection);
|
|
|
+ this.billboardCollection = this.viewer.scene.primitives.add(new Cesium.BillboardCollection());
|
|
|
+ this.polylineCollection = this.viewer.scene.primitives.add(new Cesium.PolylineCollection());
|
|
|
+ this.createAllControls();
|
|
|
}
|
|
|
+ }
|
|
|
+
|
|
|
+ // 缩放
|
|
|
+ doScale(dx, dy) {
|
|
|
+ const scaleDelta = (dx + dy) * 0.01;
|
|
|
+ const scale = Math.max(0.1, 1 + scaleDelta);
|
|
|
+
|
|
|
+ const modelMatrix = this.entity.model.modelMatrix;
|
|
|
+ const scaleVec = new Cesium.Cartesian3(1, 1, 1);
|
|
|
+ if (this.dragAxis === 'X') scaleVec.x = scale;
|
|
|
+ if (this.dragAxis === 'Y') scaleVec.y = scale;
|
|
|
+ if (this.dragAxis === 'Z') scaleVec.z = scale;
|
|
|
+
|
|
|
+ const currentScale = Cesium.Matrix4.getScale(modelMatrix, new Cesium.Cartesian3());
|
|
|
+ const newScale = new Cesium.Cartesian3(
|
|
|
+ currentScale.x * scaleVec.x,
|
|
|
+ currentScale.y * scaleVec.y,
|
|
|
+ currentScale.z * scaleVec.z
|
|
|
+ );
|
|
|
|
|
|
- // 创建旋转矩阵
|
|
|
- const quaternion = Cesium.Quaternion.fromAxisAngle(axis, angle);
|
|
|
- const rotationMatrix = Cesium.Matrix3.fromQuaternion(quaternion);
|
|
|
+ const translation = Cesium.Matrix4.getTranslation(modelMatrix, new Cesium.Cartesian3());
|
|
|
+ const rotation = Cesium.Matrix4.getRotation(modelMatrix, new Cesium.Matrix3());
|
|
|
|
|
|
- // 获取当前位置
|
|
|
- if (this.entity.position) {
|
|
|
- const currentPosition = this.entity.position.getValue(this.viewer.clock.currentTime);
|
|
|
- if (currentPosition) {
|
|
|
- // 计算新位置(绕中心点旋转)
|
|
|
- const translation = Cesium.Matrix4.fromTranslation(currentPosition);
|
|
|
- const rotation = Cesium.Matrix4.fromTranslationRotationScale(
|
|
|
- Cesium.Vector3.ZERO,
|
|
|
- quaternion,
|
|
|
- new Cesium.Cartesian3(1, 1, 1)
|
|
|
- );
|
|
|
-
|
|
|
- Cesium.Matrix4.multiply(translation, rotation, translation);
|
|
|
-
|
|
|
- const newPosition = Cesium.Matrix4.getTranslation(translation, new Cesium.Cartesian3());
|
|
|
- this.entity.position = newPosition;
|
|
|
- }
|
|
|
+ const newModelMatrix = Cesium.Matrix4.fromTranslationRotationScale(translation, rotation, newScale);
|
|
|
+ this.entity.model.modelMatrix = newModelMatrix;
|
|
|
+ this.viewer.scene.requestRender();
|
|
|
+ }
|
|
|
+
|
|
|
+ // 旋转
|
|
|
+ doRotate(dx) {
|
|
|
+ if (!this.entity.model) return;
|
|
|
+
|
|
|
+ const center = this.entity.position.getValue ? this.entity.position.getValue(this.viewer.clock.currentTime) : this.entity.position;
|
|
|
+ const angleSensitivity = 0.005;
|
|
|
+ const angle = dx * angleSensitivity;
|
|
|
+
|
|
|
+ let rotateAxis;
|
|
|
+ if (this.dragAxis === 'X') {
|
|
|
+ rotateAxis = new Cesium.Cartesian3(1, 0, 0);
|
|
|
+ } else if (this.dragAxis === 'Y') {
|
|
|
+ rotateAxis = new Cesium.Cartesian3(0, 1, 0);
|
|
|
+ } else {
|
|
|
+ rotateAxis = new Cesium.Cartesian3(0, 0, 1);
|
|
|
}
|
|
|
|
|
|
- // 更新中心点
|
|
|
- this.center = this.getCenter();
|
|
|
-
|
|
|
- // 重新创建枢轴
|
|
|
- this.init();
|
|
|
+ const mat = Cesium.Transforms.eastNorthUpToFixedFrame(center);
|
|
|
+ const worldAxis = Cesium.Matrix4.multiplyByPoint(mat, rotateAxis, new Cesium.Cartesian3());
|
|
|
+ Cesium.Cartesian3.subtract(worldAxis, center, worldAxis);
|
|
|
+ Cesium.Cartesian3.normalize(worldAxis, worldAxis);
|
|
|
|
|
|
- this.startMousePosition = mousePosition;
|
|
|
- }
|
|
|
-
|
|
|
- scale(currentMouseCartesian) {
|
|
|
- if (!this.startMouseCartesian || !currentMouseCartesian) return;
|
|
|
+ const quat = Cesium.Quaternion.fromAxisAngle(worldAxis, angle);
|
|
|
+ const rotationMatrix = Cesium.Matrix3.fromQuaternion(quat);
|
|
|
|
|
|
- const offset = new Cesium.Cartesian3(
|
|
|
- currentMouseCartesian.x - this.startMouseCartesian.x,
|
|
|
- currentMouseCartesian.y - this.startMouseCartesian.y,
|
|
|
- currentMouseCartesian.z - this.startMouseCartesian.z
|
|
|
- );
|
|
|
+ const modelMatrix = this.entity.model.modelMatrix;
|
|
|
+ const translation = Cesium.Matrix4.getTranslation(modelMatrix, new Cesium.Cartesian3());
|
|
|
+ const scale = Cesium.Matrix4.getScale(modelMatrix, new Cesium.Cartesian3());
|
|
|
|
|
|
- // 根据选中轴计算缩放比例
|
|
|
- let scaleFactor = 1.0;
|
|
|
- if (this.activeAxis === 'X' && offset.x !== 0) {
|
|
|
- scaleFactor = 1 + offset.x * 0.01;
|
|
|
- } else if (this.activeAxis === 'Y' && offset.y !== 0) {
|
|
|
- scaleFactor = 1 + offset.y * 0.01;
|
|
|
- } else if (this.activeAxis === 'Z' && offset.z !== 0) {
|
|
|
- scaleFactor = 1 + offset.z * 0.01;
|
|
|
- }
|
|
|
+ const currentRotMatrix = Cesium.Matrix4.getRotation(modelMatrix, new Cesium.Matrix3());
|
|
|
+ const newRotMatrix = Cesium.Matrix3.multiply(currentRotMatrix, rotationMatrix, new Cesium.Matrix3());
|
|
|
|
|
|
- // 更新模型缩放
|
|
|
- if (this.entity.model) {
|
|
|
- const currentScale = this.entity.model.scale || 1.0;
|
|
|
- this.entity.model.scale = currentScale * scaleFactor;
|
|
|
- }
|
|
|
+ const newModelMatrix = Cesium.Matrix4.fromTranslationRotationScale(translation, newRotMatrix, scale);
|
|
|
|
|
|
- this.startMouseCartesian = currentMouseCartesian;
|
|
|
+ this.entity.model.modelMatrix = newModelMatrix;
|
|
|
+ this.viewer.scene.requestRender();
|
|
|
}
|
|
|
-
|
|
|
- destroy() {
|
|
|
- // 清理事件监听器
|
|
|
- if (this.handler) {
|
|
|
- this.handler.destroy();
|
|
|
- this.handler = null;
|
|
|
+
|
|
|
+ // 拾取
|
|
|
+ pick(windowPos) {
|
|
|
+ const bbs = this.billboardCollection._billboards || [];
|
|
|
+ for (const bb of bbs) {
|
|
|
+ if (!bb?.position || !bb.id) continue;
|
|
|
+ const screenPos = Cesium.SceneTransforms.wgs84ToWindowCoordinates(this.viewer.scene, bb.position);
|
|
|
+ if (!screenPos) continue;
|
|
|
+ const dist = Math.hypot(screenPos.x - windowPos.x, screenPos.y - windowPos.y);
|
|
|
+ if (dist < 50) return bb;
|
|
|
}
|
|
|
-
|
|
|
- // 清理 primitives
|
|
|
- if (this.entity.model && this.entity.model.definitionChanged) {
|
|
|
- this.entity.model.definitionChanged.removeEventListener(() => {
|
|
|
- if (this.entity.model.boundingSphere) {
|
|
|
- this.center = this.getCenter();
|
|
|
- this.radius = this.getRadius();
|
|
|
- this.init();
|
|
|
- }
|
|
|
- });
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ getAxis(axis) {
|
|
|
+ switch (axis) {
|
|
|
+ case 'X': return new Cesium.Cartesian3(1, 0, 0);
|
|
|
+ case 'Y': return new Cesium.Cartesian3(0, 1, 0);
|
|
|
+ case 'Z': return new Cesium.Cartesian3(0, 0, 1);
|
|
|
+ default: return new Cesium.Cartesian3();
|
|
|
}
|
|
|
-
|
|
|
- this.clearPrimitives();
|
|
|
-
|
|
|
- this.activePrimitive = null;
|
|
|
- this.activeAxis = null;
|
|
|
- this.dragMode = null;
|
|
|
- this.startMouseCartesian = null;
|
|
|
}
|
|
|
+
|
|
|
+ localToWorld(v) {
|
|
|
+ const mat = Cesium.Transforms.eastNorthUpToFixedFrame(this.center);
|
|
|
+ return Cesium.Matrix4.multiplyByPoint(mat, v, new Cesium.Cartesian3());
|
|
|
+ }
|
|
|
+
|
|
|
+ makeArrow(color) {
|
|
|
+ const c = document.createElement('canvas');
|
|
|
+ c.width = 32; c.height = 32;
|
|
|
+ const ctx = c.getContext('2d');
|
|
|
+ ctx.fillStyle = `rgb(${color.red * 255},${color.green * 255},${color.blue * 255})`;
|
|
|
+ ctx.beginPath();
|
|
|
+ ctx.moveTo(4, 16); ctx.lineTo(24, 16); ctx.lineTo(24, 6); ctx.lineTo(30, 16); ctx.lineTo(24, 26); ctx.closePath();
|
|
|
+ ctx.fill();
|
|
|
+ return c.toDataURL();
|
|
|
+ }
|
|
|
+
|
|
|
+ makeBox(color) {
|
|
|
+ const c = document.createElement('canvas');
|
|
|
+ c.width = 24; c.height = 24;
|
|
|
+ const ctx = c.getContext('2d');
|
|
|
+ ctx.fillStyle = `rgb(${color.red * 255},${color.green * 255},${color.blue * 255})`;
|
|
|
+ ctx.fillRect(6, 6, 12, 12);
|
|
|
+ return c.toDataURL();
|
|
|
+ }
|
|
|
+
|
|
|
+ makeRing(color) {
|
|
|
+ const c = document.createElement('canvas');
|
|
|
+ c.width = 24; c.height = 24;
|
|
|
+ const ctx = c.getContext('2d');
|
|
|
+ ctx.strokeStyle = `rgb(${color.red * 255},${color.green * 255},${color.blue * 255})`;
|
|
|
+ ctx.lineWidth = 3;
|
|
|
+ ctx.beginPath();
|
|
|
+ ctx.arc(12, 12, 8, 0, Math.PI * 2);
|
|
|
+ ctx.stroke();
|
|
|
+ return c.toDataURL();
|
|
|
+ }
|
|
|
+
|
|
|
+ cleanup() {
|
|
|
+ if (this.handler) this.handler.destroy();
|
|
|
+ if (this.billboardCollection) this.viewer.scene.primitives.remove(this.billboardCollection);
|
|
|
+ if (this.polylineCollection) this.viewer.scene.primitives.remove(this.polylineCollection);
|
|
|
+ this.viewer.scene.screenSpaceCameraController.enableInputs = true;
|
|
|
+ }
|
|
|
+
|
|
|
+ destroy() { this.cleanup(); }
|
|
|
}
|
|
|
|
|
|
-export default ModelEditor;
|
|
|
+export default ModelEditor;
|