From 1c91c5bb378993cda42d5ee53e89c7ae1c44cfc9 Mon Sep 17 00:00:00 2001 From: yuliang <398780299@qq.com> Date: Fri, 6 Jun 2025 17:05:09 +0800 Subject: [PATCH 1/4] =?UTF-8?q?=E5=B1=95=E4=BC=9A=E5=9C=B0=E5=9B=BE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/assets/images/ptr/charger.png | Bin 0 -> 6835 bytes src/assets/images/ptr/clx.png | Bin 0 -> 8831 bytes src/assets/images/ptr/ptr.png | Bin 4276 -> 12020 bytes src/core/manager/WorldModel.ts | 6 +- src/example/example1.js | 259 +++++++++++++++++++++++++----- src/modules/charger/ChargerEntity.ts | 5 + src/modules/charger/ChargerInteraction.ts | 22 +++ src/modules/charger/ChargerMeta.ts | 49 ++++++ src/modules/charger/ChargerRenderer.ts | 97 +++++++++++ src/modules/charger/index.ts | 15 ++ src/modules/clx/ClxEntity.ts | 5 + src/modules/clx/ClxInteraction.ts | 22 +++ src/modules/clx/ClxMeta.ts | 49 ++++++ src/modules/clx/ClxRenderer.ts | 97 +++++++++++ src/modules/clx/index.ts | 15 ++ src/modules/gstore/GstoreRenderer.ts | 6 +- src/modules/pallet/PalletRenderer.ts | 6 +- src/modules/ptr/PtrMeta.ts | 4 +- src/modules/ptr/PtrRenderer.ts | 7 +- src/modules/rack/RackRenderer.ts | 6 +- 20 files changed, 610 insertions(+), 60 deletions(-) create mode 100644 src/assets/images/ptr/charger.png create mode 100644 src/assets/images/ptr/clx.png create mode 100644 src/modules/charger/ChargerEntity.ts create mode 100644 src/modules/charger/ChargerInteraction.ts create mode 100644 src/modules/charger/ChargerMeta.ts create mode 100644 src/modules/charger/ChargerRenderer.ts create mode 100644 src/modules/charger/index.ts create mode 100644 src/modules/clx/ClxEntity.ts create mode 100644 src/modules/clx/ClxInteraction.ts create mode 100644 src/modules/clx/ClxMeta.ts create mode 100644 src/modules/clx/ClxRenderer.ts create mode 100644 src/modules/clx/index.ts diff --git a/src/assets/images/ptr/charger.png b/src/assets/images/ptr/charger.png new file mode 100644 index 0000000000000000000000000000000000000000..24815f1fbe251e90d7f8677d5750a31b8988c108 GIT binary patch literal 6835 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 AO#lD@ literal 0 HcmV?d00001 diff --git a/src/assets/images/ptr/ptr.png b/src/assets/images/ptr/ptr.png index b65c9570950389503e783cb79098f8ebce66fdb1..8da0d6ab1077686b092c5db6338b820f45458373 100644 GIT binary patch literal 12020 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 literal 4276 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 W_v=lsR$89`0000 { console.log('世界模型初始化完成') diff --git a/src/example/example1.js b/src/example/example1.js index 32b0ea3..dfa7bd5 100644 --- a/src/example/example1.js +++ b/src/example/example1.js @@ -7,10 +7,10 @@ export default { Dashboard: [], // 监控面板 DataTable: [], // 地图自带的数据 Trigger: [ // 触发器 - { name: 'OnOpen', fn: '' }, // 打开 - { name: 'OnReset', fn: '' }, // 仿真重置 - { name: 'OnStart', fn: '' }, // 开始仿真 - { name: 'OnStop', fn: '' } // 停止仿真 + {name: 'OnOpen', fn: ''}, // 打开 + {name: 'OnReset', fn: ''}, // 仿真重置 + {name: 'OnStart', fn: ''}, // 开始仿真 + {name: 'OnStop', fn: ''} // 停止仿真 ], gridHelper: { // 网格辅助线 axesEnabled: true, // 是否显示中心轴 @@ -93,11 +93,11 @@ export default { bays: [ // 每列的配置 { bayWidth: 1.4, // 列的宽度 - levelHeight: [ 1.4, 1.4, 1.4 ] // 每层的高度 + levelHeight: [1.4, 1.4, 1.4] // 每层的高度 }, - {bayWidth: 1.4, levelHeight: [ 1.4, 1.4, 1.4 ]}, - {bayWidth: 1.4, levelHeight: [ 1.4, 1.4, 1.4 ]}, - {bayWidth: 1.4, levelHeight: [ 1.4, 1.4, 1.4 ]}, + {bayWidth: 1.4, levelHeight: [1.4, 1.4, 1.4]}, + {bayWidth: 1.4, levelHeight: [1.4, 1.4, 1.4]}, + {bayWidth: 1.4, levelHeight: [1.4, 1.4, 1.4]}, ] } }, @@ -106,87 +106,258 @@ export default { t: 'measure', v: true, tf: [[-4, 0.1, 4], [90, 0, 0], [0.25, 0.25, 0.1]], - dt: { in: [], out: [], center: ['P2'] } + dt: {in: [], out: [], center: ['P2']} }, { id: 'P2', t: 'measure', v: true, tf: [[5, 0.1, 4], [90, 0, 0], [0.25, 0.25, 0.1]], - dt: { in: [], out: [], center: ['P1', 'P3'] } + dt: {in: [], out: [], center: ['P1', 'P3']} }, { id: 'P3', t: 'measure', v: true, tf: [[5, 0.1, 6.25], [90, 0, 0], [0.25, 0.25, 0.1]], - dt: { in: [], out: [], center: ['P2'] } + dt: {in: [], out: [], center: ['P2']} }, { id: '39zML1rnSOOQGQYQ2YUMGy', t: 'way', v: true, tf: [[-4, 0.1, 2], [90, 0, 0], [0.25, 0.25, 0.1]], - dt: { in: [], out: [], center: ['6wrGKiVJniwgKkoggOoEy6'] } + dt: {in: [], out: [], center: ['6wrGKiVJniwgKkoggOoEy6']} }, { id: '6wrGKiVJniwgKkoggOoEy6', t: 'way', v: true, tf: [[5, 0.1, 2], [90, 0, 0], [0.25, 0.25, 0.1]], - dt: { in: [], out: [], center: ['39zML1rnSOOQGQYQ2YUMGy'] } + dt: {in: [], out: [], center: ['39zML1rnSOOQGQYQ2YUMGy']} }, { id: '6UhIIw9QPYh6acwyW8OSGs', t: 'gstore', v: true, tf: [[-1, 0.1, 0.55], [0, 0, 0], [1.5, 1.2, 0.1]], - dt: { in: [], out: [], center: [], storeWidth: 1.4, storeDepth: 1.4 } + dt: {in: [], out: [], center: [], storeWidth: 1.4, storeDepth: 1.4} }, { id: '1D0WSRPj8JJJwIcmA0UMqG', t: 'gstore', v: true, tf: [[0.75, 0.1, 0.55], [0, 0, 0], [1.5, 1.2, 0.1]], - dt: { in: [], out: [], center: [], storeWidth: 1.4, storeDepth: 1.4 } + dt: {in: [], out: [], center: [], storeWidth: 1.4, storeDepth: 1.4} }, { id: 'gstore3', t: 'gstore', v: true, tf: [[3, 0.1, 0.55], [0, 0, 0], [1.5, 1.2, 0.1]], - dt: { in: [], out: [], center: [], storeWidth: 1.4, storeDepth: 1.4 } - },{ + dt: {in: [], out: [], center: [], storeWidth: 1.4, storeDepth: 1.4} + }, { id: 'pallet1', t: 'pallet', v: true, tf: [[0.75, 0.075, 0.55], [0, 0, 0], [1.5, 1.2, 0.1]], - dt: { in: [], out: [], center: [], palletWidth: 1, palletDepth: 1.2 } + dt: {in: [], out: [], center: [], palletWidth: 1, palletDepth: 1.2} }, { id: 'pallet2', t: 'pallet', v: true, tf: [[3, 0.075, 0.55], [0, 0, 0], [1.5, 1.2, 0.1]], - dt: { in: [], out: [], center: [], palletWidth: 1, palletDepth: 1.2 } + dt: {in: [], out: [], center: [], palletWidth: 1, palletDepth: 1.2} }, { id: 'ptr1', t: 'ptr', v: true, tf: [[0.75, 0.075, 2], [0, 0, 0], [1.5, 1.2, 0.1]], - dt: { in: [], out: [], center: [], ptrWidth: 1.5, ptrDepth: 1.5, ptrHeight: 1.98 } + dt: {in: [], out: [], center: [], ptrWidth: 1.5, ptrDepth: 1.5, ptrHeight: 1.98} }, { id: 'ptr2', t: 'ptr', v: true, tf: [[3, 0.075, 2], [0, 0, 0], [1.5, 1.2, 0.1]], - dt: { in: [], out: [], center: [], ptrWidth: 1.5, ptrDepth: 1.5, ptrHeight: 1.98 } + dt: {in: [], out: [], center: [], ptrWidth: 1.5, ptrDepth: 1.5, ptrHeight: 1.98} }, { id: 'pallet3', t: 'pallet', v: true, - tf: [[3, 0.175, 1.9], [0, 0, 0], [1.5, 1.2, 0.1]], - dt: { in: [], out: [], center: [], palletWidth: 1, palletDepth: 1.2 } + tf: [[3, 0.175, 1.88], [0, 0, 0], [1.5, 1.2, 0.1]], + dt: {in: [], out: [], center: [], palletWidth: 1, palletDepth: 1.2} }, { id: 'pallet4', t: 'pallet', v: true, tf: [[0.75, 0.175, 3.5], [0, 0, 0], [1.5, 1.2, 0.1]], - dt: { in: [], out: [], center: [], palletWidth: 1, palletDepth: 1.2 } + dt: {in: [], out: [], center: [], palletWidth: 1, palletDepth: 1.2} } ] + }, + { + catalogCode: 'f2', t: 'floor', // 楼层 + items: [{ + id: 'rack1', + t: 'rack', + v: true, + tf: [[4.196, 0.1, 5.882], [0, 270, 0], [1, 1, 1]], + dt: { + rackDepth: 1, + rackWidth: 5.1, + rackHeight: 4.2, + levelCount: 3, + bayCount: 4, + hideFloor: false, + extendColumns: true, + columnSpacing: 1, + bays: [ + {bayWidth: 1.275, levelHeight: [1.4, 1.4, 1.4]}, + {bayWidth: 1.275, levelHeight: [1.4, 1.4, 1.4]}, + {bayWidth: 1.275, levelHeight: [1.4, 1.4, 1.4]}, + {bayWidth: 1.275, levelHeight: [1.4, 1.4, 1.4]}], + center: [], + in: [], + out: [] + } + }, {id: '3ExXFSuV9WB2WMY2Quyq6L', t: 'measure', v: true, tf: [[0, 0.1, 0], [90, 0, 0], [0.1, 0.1, 0.1]], dt: {in: [], out: [], center: ['4YZKo6XtvL2migaIUmakAr', '7Ik2sRdDZy8Q6sC00AaqCv']}}, { + id: '3ExXFSuV9WB2WMY2Quyq6L', + t: 'measure', + v: true, + tf: [[0, 0.1, 0], [90, 0, 0], [0.1, 0.1, 0.1]], + dt: {in: [], out: [], center: ['4YZKo6XtvL2migaIUmakAr', '7Ik2sRdDZy8Q6sC00AaqCv']} + }, {id: '4YZKo6XtvL2migaIUmakAr', t: 'measure', v: true, tf: [[8.4, 0.1, 0], [90, 0, 0], [0.1, 0.1, 0.1]], dt: {in: [], out: [], center: ['3ExXFSuV9WB2WMY2Quyq6L', '3cdb6OHkp132soSsgW8McA']}}, { + id: '3cdb6OHkp132soSsgW8McA', + t: 'measure', + v: true, + tf: [[8.4, 0.1, 9], [90, 0, 0], [0.1, 0.1, 0.1]], + dt: {in: [], out: [], center: ['4YZKo6XtvL2migaIUmakAr', '7Ik2sRdDZy8Q6sC00AaqCv']} + }, {id: '7Ik2sRdDZy8Q6sC00AaqCv', t: 'measure', v: true, tf: [[0, 0.1, 9], [90, 0, 0], [0.1, 0.1, 0.1]], dt: {in: [], out: [], center: ['3cdb6OHkp132soSsgW8McA', '3ExXFSuV9WB2WMY2Quyq6L']}}, { + id: '6Vu3dX1V7Si0ISWIiCkoEh', + t: 'gstore', + v: true, + tf: [[1.5, 0.1, 0.63], [0, 0, 0], [1, 1, 1]], + dt: {in: [], out: [], center: [], storeWidth: 1.1, storeDepth: 1.3} + }, {id: '592UY0EMScbwIyQqgs8aAs', t: 'gstore', v: true, tf: [[3.9, 0.1, 0.63], [0, 0, 0], [1, 1, 1]], dt: {in: [], out: [], center: [], storeWidth: 1.1, storeDepth: 1.3}}, { + id: '38TYyVWMGLf8OogQMIiSOz', + t: 'gstore', + v: true, + tf: [[7.1, 0.1, 2.865], [0, 90, 0], [1, 1, 1]], + dt: {in: [], out: [], center: [], storeWidth: 1.1, storeDepth: 1.3} + }, {id: '1hAaZ1xtvukZowAKeWAcqs', t: 'gstore', v: true, tf: [[7.1, 0.1, 4.35], [0, 90, 0], [1, 1, 1]], dt: {in: [], out: [], center: [], storeWidth: 1.1, storeDepth: 1.3}}, { + id: '28GxDYUqDwZc2WsOgMU2wi', + t: 'gstore', + v: true, + tf: [[7.1, 0.1, 6.75], [0, 90, 0], [1, 1, 1]], + dt: {in: [], out: [], center: [], storeWidth: 1.1, storeDepth: 1.3} + }, {id: '2fWOnUmFpvYyCWEqAyU0QC', t: 'way', v: true, tf: [[1.5, 0.1, 2.13], [90, 0, 0], [0.25, 0.25, 0.1]], dt: {in: [], out: [], center: ['09PTEMUnACWY0MUG4qmk0r']}}, { + id: '09PTEMUnACWY0MUG4qmk0r', + t: 'way', + v: true, + tf: [[2.7, 0.1, 2.13], [90, 0, 0], [0.25, 0.25, 0.1]], + dt: {in: [], out: [], center: ['2fWOnUmFpvYyCWEqAyU0QC', '2CSDVrpqthaiQuyWUymCwy', '0mVU9FacN1fmCAmQqwWgIZ']} + }, {id: '2CSDVrpqthaiQuyWUymCwy', t: 'way', v: true, tf: [[3.9, 0.1, 2.13], [90, 0, 0], [0.25, 0.25, 0.1]], dt: {in: [], out: [], center: ['09PTEMUnACWY0MUG4qmk0r']}}, { + id: '0mVU9FacN1fmCAmQqwWgIZ', + t: 'way', + v: true, + tf: [[2.7, 0.1, 2.832], [90, 0, 0], [0.25, 0.25, 0.1]], + dt: {in: [], out: [], center: ['09PTEMUnACWY0MUG4qmk0r', '7LuzEYQQI7OQcEUekEqWcm']} + }, {id: '7LuzEYQQI7OQcEUekEqWcm', t: 'way', v: true, tf: [[2.7, 0.1, 3.932], [90, 0, 0], [0.25, 0.25, 0.1]], dt: {in: [], out: [], center: ['0mVU9FacN1fmCAmQqwWgIZ', '2RForJhOHXtcw0gq8mYAMh']}}, { + id: '2RForJhOHXtcw0gq8mYAMh', + t: 'way', + v: true, + tf: [[2.7, 0.1, 4.582], [90, 0, 0], [0.25, 0.25, 0.1]], + dt: {in: [], out: [], center: ['7LuzEYQQI7OQcEUekEqWcm', '32vDSCKBrgMWycW0ySIgsJ']} + }, {id: '32vDSCKBrgMWycW0ySIgsJ', t: 'way', v: true, tf: [[2.7, 0.1, 5.232], [90, 0, 0], [0.25, 0.25, 0.1]], dt: {in: [], out: [], center: ['2RForJhOHXtcw0gq8mYAMh', '0wcYKcGQialFQCGkAa6aYB']}}, { + id: '0wcYKcGQialFQCGkAa6aYB', + t: 'way', + v: true, + tf: [[2.7, 0.1, 5.882], [90, 0, 0], [0.25, 0.25, 0.1]], + dt: {in: [], out: [], center: ['32vDSCKBrgMWycW0ySIgsJ', '55g6mUWBdozg4m2ueUEUsy']} + }, {id: '55g6mUWBdozg4m2ueUEUsy', t: 'way', v: true, tf: [[2.7, 0.1, 6.532], [90, 0, 0], [0.25, 0.25, 0.1]], dt: {in: [], out: [], center: ['0wcYKcGQialFQCGkAa6aYB', '5iKoIUBhnU08EM0IsoyOSW']}}, { + id: '5iKoIUBhnU08EM0IsoyOSW', + t: 'way', + v: true, + tf: [[2.7, 0.1, 7.632], [90, 0, 0], [0.25, 0.25, 0.1]], + dt: {in: [], out: [], center: ['55g6mUWBdozg4m2ueUEUsy']} + }, { + id: '3ZP01pHXJRuyeg24oCaaMq', + t: 'way', + v: true, + tf: [[5.65, 0.1, 2.13], [90, 0, 0], [0.25, 0.25, 0.1]], + dt: {in: [], out: [], center: ['5onDSGuIKBpUQo6g0EIsuS']} + }, {id: '5onDSGuIKBpUQo6g0EIsuS', t: 'way', v: true, tf: [[5.65, 0.1, 2.865], [90, 0, 0], [0.25, 0.25, 0.1]], dt: {in: [], out: [], center: ['3ZP01pHXJRuyeg24oCaaMq', '41A0CKR8cFW8wKkcSMQ4uk']}}, { + id: '41A0CKR8cFW8wKkcSMQ4uk', + t: 'way', + v: true, + tf: [[5.65, 0.1, 3.932], [90, 0, 0], [0.25, 0.25, 0.1]], + dt: {in: [], out: [], center: ['5onDSGuIKBpUQo6g0EIsuS', '4PunEz5C3Xk66EaOgMEuMq']} + }, {id: '4PunEz5C3Xk66EaOgMEuMq', t: 'way', v: true, tf: [[5.65, 0.1, 4.348], [90, 0, 0], [0.25, 0.25, 0.1]], dt: {in: [], out: [], center: ['41A0CKR8cFW8wKkcSMQ4uk', '6oCW8i0dpRtuCEIWIaAcQi']}}, { + id: '6oCW8i0dpRtuCEIWIaAcQi', + t: 'way', + v: true, + tf: [[5.65, 0.1, 5.232], [90, 0, 0], [0.25, 0.25, 0.1]], + dt: {in: [], out: [], center: ['4PunEz5C3Xk66EaOgMEuMq', '3C9Z8c6oxQbWcS4uSGkC8b']} + }, {id: '3C9Z8c6oxQbWcS4uSGkC8b', t: 'way', v: true, tf: [[5.65, 0.1, 5.882], [90, 0, 0], [0.25, 0.25, 0.1]], dt: {in: [], out: [], center: ['6oCW8i0dpRtuCEIWIaAcQi', '1jJX8KZLMPSSCwuCOU6AQz']}}, { + id: '1jJX8KZLMPSSCwuCOU6AQz', + t: 'way', + v: true, + tf: [[5.65, 0.1, 6.532], [90, 0, 0], [0.25, 0.25, 0.1]], + dt: {in: [], out: [], center: ['3C9Z8c6oxQbWcS4uSGkC8b', '0aJ81sOKqm9FYo60AIQmMG']} + }, {id: '0aJ81sOKqm9FYo60AIQmMG', t: 'way', v: true, tf: [[5.65, 0.1, 6.744], [90, 0, 0], [0.25, 0.25, 0.1]], dt: {in: [], out: [], center: ['1jJX8KZLMPSSCwuCOU6AQz', '2qtxSDVn30EcI2uY4W0CWf']}}, { + id: '2qtxSDVn30EcI2uY4W0CWf', + t: 'way', + v: true, + tf: [[5.65, 0.1, 7.632], [90, 0, 0], [0.25, 0.25, 0.1]], + dt: {in: [], out: [], center: ['0aJ81sOKqm9FYo60AIQmMG']} + }, { + id: 'ptr1', + t: 'ptr', + v: true, + tf: [[5.65, 0.1, 2.865], [0, -90, 0], [1, 1, 1]], + dt: {in: [], out: [], center: [], ptrWidth: 1.5, ptrDepth: 1.5, ptrHeight: 1.98} + }, { + id: 'clx1', + t: 'clx', + v: true, + tf: [[1.5, 0.1, 2.13], [0, 0, 0], [1, 1, 1]], + dt: {in: [], out: [], center: [], clxWidth: 1.65, clxDepth: 1.65, clxHeight: 3.393} + }, { + id: 'charger1', + t: 'charger', + v: true, + tf: [[2.696, 0.1, 8.75], [0, 0, 0], [1, 1, 1]], + dt: {in: [], out: [], center: [], chargerWidth: 0.53, chargerDepth: 0.275, clxHeight: 0.3} + }, { + id: 'charger2', + t: 'charger', + v: true, + tf: [[5.655, 0.1, 8.75], [0, 0, 0], [1, 1, 1]], + dt: {in: [], out: [], center: [], chargerWidth: 0.53, chargerDepth: 0.275, clxHeight: 0.3} + }, { + id: 'pallet1122', + t: 'pallet', + v: true, + tf: [[1.5, 0.1, 0.63], [0, 0, 0], [1, 1, 1]], + dt: {in: [], out: [], center: [], palletWidth: 1, palletDepth: 1.2} + }, { + id: 'pallet1123', + t: 'pallet', + v: true, + tf: [[7.100, 0.1, 4.35], [0, 90, 0], [1, 1, 1]], + dt: {in: [], out: [], center: [], palletWidth: 1, palletDepth: 1.2} + }, { + id: 'pallet1124', + t: 'pallet', + v: true, + tf: [[4.196, 0.1, 3.95], [0, 90, 0], [1, 1, 1]], + dt: {in: [], out: [], center: [], palletWidth: 1, palletDepth: 1.2} + }, { + id: 'pallet1125', + t: 'pallet', + v: true, + tf: [[4.196, 0.1, 5.225], [0, 90, 0], [1, 1, 1]], + dt: {in: [], out: [], center: [], palletWidth: 1, palletDepth: 1.2} + }, { + id: 'pallet1126', + t: 'pallet', + v: true, + tf: [[4.196, 0.1, 7.775], [0, 90, 0], [1, 1, 1]], + dt: {in: [], out: [], center: [], palletWidth: 1, palletDepth: 1.2} + }] } ], elevator: [], // 电梯 @@ -196,41 +367,41 @@ export default { { label: '仓库楼层', // 目录分组名 items: [ - { catalogCode: '-f1', label: '地下室 (-f1)' }, // 目录项 - { catalogCode: 'f1', label: '一楼 (f1)' }, - { catalogCode: 'f2', label: '二楼 (f2)' }, - { catalogCode: 'OUT', label: '外场 (OUT)' }, - { catalogCode: 'fe', label: '楼层电梯 (fe)' } + {catalogCode: '-f1', label: '地下室 (-f1)'}, // 目录项 + {catalogCode: 'f1', label: '一楼 (f1)'}, + {catalogCode: 'f2', label: '二楼 (f2)'}, + {catalogCode: 'OUT', label: '外场 (OUT)'}, + {catalogCode: 'fe', label: '楼层电梯 (fe)'} ] }, { label: '密集库区域', items: [ - { catalogCode: 'm1', label: 'M1 (m1)' }, - { catalogCode: 'm2', label: 'M2 (m2)' }, - { catalogCode: 'm3', label: 'M3 (m3)' }, - { catalogCode: 'm4', label: 'M4 (m4)' }, - { catalogCode: 'me', label: '提升机 (me)' } + {catalogCode: 'm1', label: 'M1 (m1)'}, + {catalogCode: 'm2', label: 'M2 (m2)'}, + {catalogCode: 'm3', label: 'M3 (m3)'}, + {catalogCode: 'm4', label: 'M4 (m4)'}, + {catalogCode: 'me', label: '提升机 (me)'} ] }, { label: '多穿库A', items: [ - { catalogCode: 'd1', label: 'D1 (d1)' }, - { catalogCode: 'd2', label: 'D2 (d2)' }, - { catalogCode: 'd3', label: 'D3 (d3)' }, - { catalogCode: 'd4', label: 'D4 (d4)' }, - { catalogCode: 'de1', label: '提升机 (de1)' } + {catalogCode: 'd1', label: 'D1 (d1)'}, + {catalogCode: 'd2', label: 'D2 (d2)'}, + {catalogCode: 'd3', label: 'D3 (d3)'}, + {catalogCode: 'd4', label: 'D4 (d4)'}, + {catalogCode: 'de1', label: '提升机 (de1)'} ] }, { label: '多穿库B', items: [ - { catalogCode: 'e1', label: 'E1 (e1)' }, - { catalogCode: 'e2', label: 'E2 (e2)' }, - { catalogCode: 'e3', label: 'E3 (e3)' }, - { catalogCode: 'e4', label: 'E4 (e4)' }, - { catalogCode: 'ee1', label: '提升机 (ee1)' } + {catalogCode: 'e1', label: 'E1 (e1)'}, + {catalogCode: 'e2', label: 'E2 (e2)'}, + {catalogCode: 'e3', label: 'E3 (e3)'}, + {catalogCode: 'e4', label: 'E4 (e4)'}, + {catalogCode: 'ee1', label: '提升机 (ee1)'} ] } ] diff --git a/src/modules/charger/ChargerEntity.ts b/src/modules/charger/ChargerEntity.ts new file mode 100644 index 0000000..dc7878c --- /dev/null +++ b/src/modules/charger/ChargerEntity.ts @@ -0,0 +1,5 @@ +import BaseEntity from '@/core/base/BaseItemEntity.ts' + +export default class ChargerEntity extends BaseEntity { + +} diff --git a/src/modules/charger/ChargerInteraction.ts b/src/modules/charger/ChargerInteraction.ts new file mode 100644 index 0000000..28b4173 --- /dev/null +++ b/src/modules/charger/ChargerInteraction.ts @@ -0,0 +1,22 @@ +import BaseInteraction from '@/core/base/BaseInteraction.ts' +import * as THREE from 'three' + +export default class ChargerInteraction extends BaseInteraction { + + get isSinglePointMode(): boolean { + return true + } + + constructor(itemTypeName: string) { + super(itemTypeName) + } + + createPointOfItem(item: ItemJson, point: THREE.Vector3): ItemJson { + item = super.createPointOfItem(item, point) + + // 创建一个地堆货架 + item.dt.palletWidth = 1 // 宽度 + item.dt.palletDepth = 1.2 // 深度 + return item + } +} diff --git a/src/modules/charger/ChargerMeta.ts b/src/modules/charger/ChargerMeta.ts new file mode 100644 index 0000000..cbf8f74 --- /dev/null +++ b/src/modules/charger/ChargerMeta.ts @@ -0,0 +1,49 @@ +import type { IMeta } from '@/core/base/IMeta.ts' + +export default [ + { field: 'uuid', editor: 'UUID', label: 'uuid', readonly: true, category: 'basic' }, + { field: 'name', editor: 'TextInput', label: '名称', category: 'basic' }, + { field: 'dt.label', editor: 'TextInput', label: '标签', category: 'basic' }, + { editor: 'TransformEditor', category: 'basic' }, + { field: 'dt.color', editor: 'Color', label: '颜色', category: 'basic' }, + { editor: '-', category: 'basic' }, + + { field: 'dt.chargerWidth', editor: 'NumberInput', label: '充电桩宽度', category: 'basic' }, + { field: 'dt.chargerDepth', editor: 'NumberInput', label: '充电桩深度', category: 'basic' }, + /** + * dt.bays 5列3层货架示例 + * { + * dt: { + * rackDepth: 1.1, // 货架深度 + * levelCount: 3, // 总层数 + * bayCount: 5, // 总列数 + * hideFloor: false, // 隐藏底板 + * extendColumns: true, // 扩展挡板 + * columnSpacing: 1, // 支脚跨越 + * bays: [ // 每列的配置 + * { + * bayWidth: 1.6, // 列的宽度 + * levelHeight: [ 1.4, 1.4, 1.4 ] // 每层的高度 + * }, + * {bayWidth: 1.6, levelHeight: [ 1.4, 1.4, 1.4 ]}, + * {bayWidth: 1.6, levelHeight: [ 1.4, 1.4, 1.4 ]}, + * {bayWidth: 1.6, levelHeight: [ 1.4, 1.4, 1.4 ]}, + * {bayWidth: 1.6, levelHeight: [ 1.4, 1.4, 1.4 ]}, + * ] + * } + * } + * + * + * + * + * + * + * + */ + + + { field: 'tf', editor: 'InOutCenterEditor', category: 'basic' }, + { field: 'dt.selectable', editor: 'Switch', label: '可选中', category: 'basic' }, + { field: 'dt.protected', editor: 'Switch', label: '受保护', category: 'basic' }, + { field: 'visible', editor: 'Switch', label: '可见', category: 'basic' } +] as IMeta diff --git a/src/modules/charger/ChargerRenderer.ts b/src/modules/charger/ChargerRenderer.ts new file mode 100644 index 0000000..869b18b --- /dev/null +++ b/src/modules/charger/ChargerRenderer.ts @@ -0,0 +1,97 @@ +import * as THREE from 'three' +import BaseRenderer from '@/core/base/BaseRenderer.ts' +import { Line2 } from 'three/examples/jsm/lines/Line2.js' +import { LineGeometry } from 'three/examples/jsm/lines/LineGeometry.js' +import { LineMaterial } from 'three/examples/jsm/lines/LineMaterial.js' +import {decimalSumBy} from "@/core/ModelUtils"; +import Constract from '@/core/Constract.ts' +import chargerUrl from '@/assets/images/ptr/charger.png' + +/** + * 充电器渲染器 + */ +export default class ChargerRenderer extends BaseRenderer { + static POINT_NAME = 'charger' + + pointMaterial: THREE.Material + + /** + * 默认点的高度, 防止和地面重合 + */ + readonly defulePositionY: number = Constract.HEIGHT_WAY + readonly defaultScale: THREE.Vector3 = new THREE.Vector3(1, 1, 1) + readonly defaultRotation: THREE.Vector3 = new THREE.Vector3(0, 0, 0) + readonly defaultLineWidth: number = 0.15 + + constructor(itemTypeName: string) { + super(itemTypeName) + } + + /** + * 所有的点,必须使用 storeWidth/storeDepth, 改TF无效 + */ + override afterCreateOrUpdatePoint(item: ItemJson, option: RendererCudOption, objects: THREE.Object3D[]) { + super.afterCreateOrUpdatePoint(item, option, objects) + + const point = objects[0] + // point.position.y = this.defulePositionY + // point.scale.set(_.sumBy(item.dt.bays, b=>b.bayWidth), this.defaultScale.y, item.dt.rackDepth) + point.rotation.set( + THREE.MathUtils.degToRad(item.tf[1][0]), + THREE.MathUtils.degToRad(item.tf[1][1]), + THREE.MathUtils.degToRad(item.tf[1][2]) + ) + } + + + createLineBasic(start: ItemJson, end: ItemJson, type: LinkType): THREE.Object3D[] { + throw new Error('not allow store line.') + } + + updateLine(start: ItemJson, end: ItemJson, type: LinkType, option?: RendererCudOption) { + throw new Error('not allow store line.') + } + + + createPoint(item: ItemJson, option?: RendererCudOption): THREE.Object3D[] { + // 创建平面几何体 + if (!item.dt.chargerWidth || !item.dt.chargerDepth) { + return [] + } + + const textureLoader = new THREE.TextureLoader() + const texture = textureLoader.load(chargerUrl) + + const group = new THREE.Group() + group.name = ChargerRenderer.POINT_NAME + + // 绘制背景矩形框 + const planeGeometry = new THREE.PlaneGeometry(item.dt.chargerWidth, item.dt.chargerDepth); + planeGeometry.rotateX(-Math.PI / 2) + const planeMaterial = new THREE.MeshLambertMaterial({ + map: texture, // 颜色贴图 + transparent: true, // 允许透明纹理 + }); + const planeMesh = new THREE.Mesh(planeGeometry, planeMaterial); + group.add(planeMesh) + + // 设置位置 + group.position.set(item.tf[0][0], item.tf[0][1], item.tf[0][2]) + + const points = [group] + this.fillObjectUserDataFromItem(item, ...points) + this.afterCreateOrUpdatePoint(item, option, points) + this.tempViewport.entityManager.appendObject(item.id, points) + this.appendToScene(...points) + return points + } + + dispose() { + super.dispose() + this.pointMaterial?.dispose() + } + + createPointBasic(item: ItemJson, option?: RendererCudOption): Object3D[] { + return []; + } +} diff --git a/src/modules/charger/index.ts b/src/modules/charger/index.ts new file mode 100644 index 0000000..1085ad5 --- /dev/null +++ b/src/modules/charger/index.ts @@ -0,0 +1,15 @@ +import { defineModule } from '@/core/manager/ModuleManager.ts' +import ChargerRenderer from './ChargerRenderer.ts' +import ChargerEntity from './ChargerEntity.ts' +import ChargerMeta from './ChargerMeta.ts' +import ChargerInteraction from './ChargerInteraction.ts' + +export const ITEM_TYPE_NAME = 'charger' + +export default defineModule({ + name: ITEM_TYPE_NAME, + renderer: new ChargerRenderer(ITEM_TYPE_NAME), + interaction: new ChargerInteraction(ITEM_TYPE_NAME), + meta: ChargerMeta, + entity: ChargerEntity +}) diff --git a/src/modules/clx/ClxEntity.ts b/src/modules/clx/ClxEntity.ts new file mode 100644 index 0000000..c81c09a --- /dev/null +++ b/src/modules/clx/ClxEntity.ts @@ -0,0 +1,5 @@ +import BaseEntity from '@/core/base/BaseItemEntity.ts' + +export default class ClxEntity extends BaseEntity { + +} diff --git a/src/modules/clx/ClxInteraction.ts b/src/modules/clx/ClxInteraction.ts new file mode 100644 index 0000000..b6bde8b --- /dev/null +++ b/src/modules/clx/ClxInteraction.ts @@ -0,0 +1,22 @@ +import BaseInteraction from '@/core/base/BaseInteraction.ts' +import * as THREE from 'three' + +export default class ClxInteraction extends BaseInteraction { + + get isSinglePointMode(): boolean { + return true + } + + constructor(itemTypeName: string) { + super(itemTypeName) + } + + createPointOfItem(item: ItemJson, point: THREE.Vector3): ItemJson { + item = super.createPointOfItem(item, point) + + // 创建一个地堆货架 + item.dt.palletWidth = 1 // 宽度 + item.dt.palletDepth = 1.2 // 深度 + return item + } +} diff --git a/src/modules/clx/ClxMeta.ts b/src/modules/clx/ClxMeta.ts new file mode 100644 index 0000000..24ad4fc --- /dev/null +++ b/src/modules/clx/ClxMeta.ts @@ -0,0 +1,49 @@ +import type { IMeta } from '@/core/base/IMeta.ts' + +export default [ + { field: 'uuid', editor: 'UUID', label: 'uuid', readonly: true, category: 'basic' }, + { field: 'name', editor: 'TextInput', label: '名称', category: 'basic' }, + { field: 'dt.label', editor: 'TextInput', label: '标签', category: 'basic' }, + { editor: 'TransformEditor', category: 'basic' }, + { field: 'dt.color', editor: 'Color', label: '颜色', category: 'basic' }, + { editor: '-', category: 'basic' }, + + { field: 'dt.clxWidth', editor: 'NumberInput', label: 'CLX宽度', category: 'basic' }, + { field: 'dt.clxDepth', editor: 'NumberInput', label: 'CLX深度', category: 'basic' }, + /** + * dt.bays 5列3层货架示例 + * { + * dt: { + * rackDepth: 1.1, // 货架深度 + * levelCount: 3, // 总层数 + * bayCount: 5, // 总列数 + * hideFloor: false, // 隐藏底板 + * extendColumns: true, // 扩展挡板 + * columnSpacing: 1, // 支脚跨越 + * bays: [ // 每列的配置 + * { + * bayWidth: 1.6, // 列的宽度 + * levelHeight: [ 1.4, 1.4, 1.4 ] // 每层的高度 + * }, + * {bayWidth: 1.6, levelHeight: [ 1.4, 1.4, 1.4 ]}, + * {bayWidth: 1.6, levelHeight: [ 1.4, 1.4, 1.4 ]}, + * {bayWidth: 1.6, levelHeight: [ 1.4, 1.4, 1.4 ]}, + * {bayWidth: 1.6, levelHeight: [ 1.4, 1.4, 1.4 ]}, + * ] + * } + * } + * + * + * + * + * + * + * + */ + + + { field: 'tf', editor: 'InOutCenterEditor', category: 'basic' }, + { field: 'dt.selectable', editor: 'Switch', label: '可选中', category: 'basic' }, + { field: 'dt.protected', editor: 'Switch', label: '受保护', category: 'basic' }, + { field: 'visible', editor: 'Switch', label: '可见', category: 'basic' } +] as IMeta diff --git a/src/modules/clx/ClxRenderer.ts b/src/modules/clx/ClxRenderer.ts new file mode 100644 index 0000000..07b77e2 --- /dev/null +++ b/src/modules/clx/ClxRenderer.ts @@ -0,0 +1,97 @@ +import * as THREE from 'three' +import BaseRenderer from '@/core/base/BaseRenderer.ts' +import { Line2 } from 'three/examples/jsm/lines/Line2.js' +import { LineGeometry } from 'three/examples/jsm/lines/LineGeometry.js' +import { LineMaterial } from 'three/examples/jsm/lines/LineMaterial.js' +import {decimalSumBy} from "@/core/ModelUtils"; +import Constract from '@/core/Constract.ts' +import clxUrl from '@/assets/images/ptr/clx.png' + +/** + * clx渲染器 + */ +export default class ClxRenderer extends BaseRenderer { + static POINT_NAME = 'clx' + + pointMaterial: THREE.Material + + /** + * 默认点的高度, 防止和地面重合 + */ + readonly defulePositionY: number = Constract.HEIGHT_WAY + readonly defaultScale: THREE.Vector3 = new THREE.Vector3(1, 1, 1) + readonly defaultRotation: THREE.Vector3 = new THREE.Vector3(0, 0, 0) + readonly defaultLineWidth: number = 0.15 + + constructor(itemTypeName: string) { + super(itemTypeName) + } + + /** + * 所有的点,必须使用 storeWidth/storeDepth, 改TF无效 + */ + override afterCreateOrUpdatePoint(item: ItemJson, option: RendererCudOption, objects: THREE.Object3D[]) { + super.afterCreateOrUpdatePoint(item, option, objects) + + const point = objects[0] + // point.position.y = this.defulePositionY + // point.scale.set(_.sumBy(item.dt.bays, b=>b.bayWidth), this.defaultScale.y, item.dt.rackDepth) + point.rotation.set( + THREE.MathUtils.degToRad(item.tf[1][0]), + THREE.MathUtils.degToRad(item.tf[1][1]), + THREE.MathUtils.degToRad(item.tf[1][2]) + ) + } + + + createLineBasic(start: ItemJson, end: ItemJson, type: LinkType): THREE.Object3D[] { + throw new Error('not allow store line.') + } + + updateLine(start: ItemJson, end: ItemJson, type: LinkType, option?: RendererCudOption) { + throw new Error('not allow store line.') + } + + + createPoint(item: ItemJson, option?: RendererCudOption): THREE.Object3D[] { + // 创建平面几何体 + if (!item.dt.clxWidth || !item.dt.clxDepth) { + return [] + } + + const textureLoader = new THREE.TextureLoader() + const texture = textureLoader.load(clxUrl) + + const group = new THREE.Group() + group.name = ClxRenderer.POINT_NAME + + // 绘制背景矩形框 + const planeGeometry = new THREE.PlaneGeometry(item.dt.clxWidth, item.dt.clxDepth); + planeGeometry.rotateX(-Math.PI / 2) + const planeMaterial = new THREE.MeshLambertMaterial({ + map: texture, // 颜色贴图 + transparent: true, // 允许透明纹理 + }); + const planeMesh = new THREE.Mesh(planeGeometry, planeMaterial); + group.add(planeMesh) + + // 设置位置 + group.position.set(item.tf[0][0], item.tf[0][1], item.tf[0][2]) + + const points = [group] + this.fillObjectUserDataFromItem(item, ...points) + this.afterCreateOrUpdatePoint(item, option, points) + this.tempViewport.entityManager.appendObject(item.id, points) + this.appendToScene(...points) + return points + } + + dispose() { + super.dispose() + this.pointMaterial?.dispose() + } + + createPointBasic(item: ItemJson, option?: RendererCudOption): Object3D[] { + return []; + } +} diff --git a/src/modules/clx/index.ts b/src/modules/clx/index.ts new file mode 100644 index 0000000..6e816eb --- /dev/null +++ b/src/modules/clx/index.ts @@ -0,0 +1,15 @@ +import { defineModule } from '@/core/manager/ModuleManager.ts' +import ClxRenderer from './ClxRenderer.ts' +import ClxEntity from './ClxEntity.ts' +import ClxMeta from './ClxMeta.ts' +import ClxInteraction from './ClxInteraction.ts' + +export const ITEM_TYPE_NAME = 'clx' + +export default defineModule({ + name: ITEM_TYPE_NAME, + renderer: new ClxRenderer(ITEM_TYPE_NAME), + interaction: new ClxInteraction(ITEM_TYPE_NAME), + meta: ClxMeta, + entity: ClxEntity +}) diff --git a/src/modules/gstore/GstoreRenderer.ts b/src/modules/gstore/GstoreRenderer.ts index 2f7ea83..52e0e07 100644 --- a/src/modules/gstore/GstoreRenderer.ts +++ b/src/modules/gstore/GstoreRenderer.ts @@ -35,9 +35,9 @@ export default class GstoreRenderer extends BaseRenderer { point.position.y = this.defulePositionY // point.scale.set(item.dt.storeWidth, this.defaultScale.y, item.dt.storeDepth) point.rotation.set( - THREE.MathUtils.degToRad(this.defaultRotation.x), - THREE.MathUtils.degToRad(this.defaultRotation.y), - THREE.MathUtils.degToRad(this.defaultRotation.z) + THREE.MathUtils.degToRad(item.tf[1][0]), + THREE.MathUtils.degToRad(item.tf[1][1]), + THREE.MathUtils.degToRad(item.tf[1][2]) ) } diff --git a/src/modules/pallet/PalletRenderer.ts b/src/modules/pallet/PalletRenderer.ts index c1ca858..a43bdc6 100644 --- a/src/modules/pallet/PalletRenderer.ts +++ b/src/modules/pallet/PalletRenderer.ts @@ -37,9 +37,9 @@ export default class PalletRenderer extends BaseRenderer { //point.scale.set(_.sumBy(item.dt.bays, b=>b.bayWidth), this.defaultScale.y, item.dt.rackDepth) point.rotation.set( - THREE.MathUtils.degToRad(this.defaultRotation.x), - THREE.MathUtils.degToRad(this.defaultRotation.y), - THREE.MathUtils.degToRad(this.defaultRotation.z) + THREE.MathUtils.degToRad(item.tf[1][0]), + THREE.MathUtils.degToRad(item.tf[1][1]), + THREE.MathUtils.degToRad(item.tf[1][2]) ) } diff --git a/src/modules/ptr/PtrMeta.ts b/src/modules/ptr/PtrMeta.ts index d39f5d0..4fede36 100644 --- a/src/modules/ptr/PtrMeta.ts +++ b/src/modules/ptr/PtrMeta.ts @@ -8,8 +8,8 @@ export default [ { field: 'dt.color', editor: 'Color', label: '颜色', category: 'basic' }, { editor: '-', category: 'basic' }, - { field: 'dt.palletWidth', editor: 'NumberInput', label: '托盘深度', category: 'basic' }, - { field: 'dt.palletDepth', editor: 'NumberInput', label: '托盘深度', category: 'basic' }, + { field: 'dt.ptrWidth', editor: 'NumberInput', label: 'PTR宽度', category: 'basic' }, + { field: 'dt.ptrDepth', editor: 'NumberInput', label: 'PTR深度', category: 'basic' }, /** * dt.bays 5列3层货架示例 * { diff --git a/src/modules/ptr/PtrRenderer.ts b/src/modules/ptr/PtrRenderer.ts index 3de33b7..6233954 100644 --- a/src/modules/ptr/PtrRenderer.ts +++ b/src/modules/ptr/PtrRenderer.ts @@ -37,9 +37,9 @@ export default class PtrRenderer extends BaseRenderer { // point.position.y = this.defulePositionY // point.scale.set(_.sumBy(item.dt.bays, b=>b.bayWidth), this.defaultScale.y, item.dt.rackDepth) point.rotation.set( - THREE.MathUtils.degToRad(this.defaultRotation.x), - THREE.MathUtils.degToRad(this.defaultRotation.y), - THREE.MathUtils.degToRad(this.defaultRotation.z) + THREE.MathUtils.degToRad(item.tf[1][0]), + THREE.MathUtils.degToRad(item.tf[1][1]), + THREE.MathUtils.degToRad(item.tf[1][2]) ) } @@ -68,7 +68,6 @@ export default class PtrRenderer extends BaseRenderer { // 绘制背景矩形框 const planeGeometry = new THREE.PlaneGeometry(item.dt.ptrWidth, item.dt.ptrDepth); planeGeometry.rotateX(-Math.PI / 2) - planeGeometry.rotateY(-Math.PI / 2) const planeMaterial = new THREE.MeshLambertMaterial({ map: texture, // 颜色贴图 transparent: true, // 允许透明纹理 diff --git a/src/modules/rack/RackRenderer.ts b/src/modules/rack/RackRenderer.ts index 8701a83..fa7fbba 100644 --- a/src/modules/rack/RackRenderer.ts +++ b/src/modules/rack/RackRenderer.ts @@ -37,9 +37,9 @@ export default class RackRenderer extends BaseRenderer { //point.scale.set(_.sumBy(item.dt.bays, b=>b.bayWidth), this.defaultScale.y, item.dt.rackDepth) point.rotation.set( - THREE.MathUtils.degToRad(this.defaultRotation.x), - THREE.MathUtils.degToRad(this.defaultRotation.y), - THREE.MathUtils.degToRad(this.defaultRotation.z) + THREE.MathUtils.degToRad(item.tf[1][0]), + THREE.MathUtils.degToRad(item.tf[1][1]), + THREE.MathUtils.degToRad(item.tf[1][2]) ) } From e85311a709bc447f0a47fe9abcde3ef703db6eb6 Mon Sep 17 00:00:00 2001 From: luoyifan Date: Fri, 6 Jun 2025 17:10:59 +0800 Subject: [PATCH 2/4] =?UTF-8?q?EsDragControl2=20=E6=8B=96=E6=8B=BD?= =?UTF-8?q?=E7=AE=A1=E7=90=86=E5=99=A8=E5=AE=8C=E6=88=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/core/base/BaseRenderer.ts | 4 +- src/core/controls/EsDragControl2.ts | 265 +++++++++++++++++++++++++++++++++ src/core/engine/Viewport.ts | 28 ++-- src/model/itemType/ItemType.ts | 4 +- src/model/itemType/Toolbox.ts | 4 +- src/modules/gstore/GstoreRenderer.ts | 29 ++-- src/modules/measure/MeasureRenderer.ts | 2 +- src/modules/way/WayRenderer.ts | 2 +- 8 files changed, 306 insertions(+), 32 deletions(-) create mode 100644 src/core/controls/EsDragControl2.ts diff --git a/src/core/base/BaseRenderer.ts b/src/core/base/BaseRenderer.ts index 88056a1..1fef5cd 100644 --- a/src/core/base/BaseRenderer.ts +++ b/src/core/base/BaseRenderer.ts @@ -124,7 +124,7 @@ export default abstract class BaseRenderer { this.tempViewport.scene.add(...objects) const dragObjects = objects.filter(obj => !!obj.userData.draggable) - this.tempViewport.dragControl.setDragObjects(dragObjects, 'push') + //this.tempViewport.dragControl.setDragObjects(dragObjects, 'push') } removeFromScene(...objects: THREE.Object3D[]) { @@ -133,7 +133,7 @@ export default abstract class BaseRenderer { return } this.tempViewport.scene.remove(...objects) - this.tempViewport.dragControl.setDragObjects(objects, 'remove') + //this.tempViewport.dragControl.setDragObjects(objects, 'remove') } /** diff --git a/src/core/controls/EsDragControl2.ts b/src/core/controls/EsDragControl2.ts new file mode 100644 index 0000000..b69ea09 --- /dev/null +++ b/src/core/controls/EsDragControl2.ts @@ -0,0 +1,265 @@ +import * as THREE from 'three' +import type Viewport from '@/core/engine/Viewport.ts' +import type IControls from '@/core/controls/IControls.ts' +import { Curve } from 'three' +import { getClosestObject } from '@/core/ModelUtils.ts' +import EventBus from '@/runtime/EventBus.ts' + +/** + * DragControl2 - ThreeJS 拖拽管理器(仅限 X/Z 平面) + */ +export default class DragControl2 implements IControls { + private viewport: Viewport + private enabled: boolean = true + + private isDragging: boolean = false + private isPointerDown: boolean = false + private dragStartMouse: THREE.Vector2 = new THREE.Vector2() + + private dragShadows: THREE.Group | null = null + + init(viewport: Viewport): void { + this.viewport = viewport + + const domElement = this.viewport.renderer.domElement + domElement.addEventListener('pointermove', this.onPointerMove) + domElement.addEventListener('pointerdown', this.onPointerDown) + domElement.addEventListener('pointerup', this.onPointerUp) + domElement.addEventListener('pointerleave', this.onPointerLeave) + + domElement.style.cursor = 'auto' + } + + + /** + * 设置启用/禁用 + */ + set enable(value: boolean) { + this.enabled = value + if (!value) { + this.cleanupDrag() + } + } + + get enable(): boolean { + return this.enabled + } + + /** + * 卸载资源 + */ + dispose(): void { + const domElement = this.viewport.renderer.domElement + domElement.removeEventListener('pointermove', this.onPointerMove) + domElement.removeEventListener('pointerdown', this.onPointerDown) + domElement.removeEventListener('pointerup', this.onPointerUp) + domElement.removeEventListener('pointerleave', this.onPointerLeave) + + this.cleanupDrag() + domElement.style.cursor = 'auto' + } + + /** + * 清理拖拽状态 + */ + private cleanupDrag(): void { + if (this.isDragging || this.isPointerDown) { + this.isDragging = false + this.isPointerDown = false + this.dragStartMouse.set(NaN, NaN) + this.removeShadows() + } + } + + /** + * 获取当前鼠标坐标(归一化设备坐标) + */ + private getMousePosition(clientX: number, clientY: number): THREE.Vector2 { + const rect = this.viewport.renderer.domElement.getBoundingClientRect() + return new THREE.Vector2( + ((clientX - rect.left) / rect.width) * 2 - 1, + ((clientY - rect.top) / rect.height) * -2 + 1 + ) + } + + /** + * 射线检测,返回第一个可拖拽对象 + */ + private getIntersectedDraggableObject(mouse: THREE.Vector2): THREE.Object3D | null { + const raycaster = new THREE.Raycaster() + raycaster.setFromCamera(mouse, this.viewport.camera) + + const draggableObjects = this.viewport.entityManager._draggableObjects || [] + const intersects = raycaster.intersectObjects(draggableObjects, true) + + if (intersects.length > 0) { + return getClosestObject(intersects[0].object) + } + } + + /** + * 创建拖拽阴影 + */ + private createShadows(objects: THREE.Object3D[]): void { + this.removeShadows() + + console.log('createShadows', objects.map(obj => obj.name)) + + this.dragShadows = new THREE.Group() + for (const obj of objects) { + if (!obj.userData.entityId) { + console.error('Object does not have entityId:', obj.name) + continue // 跳过没有 entityId 的对象 + } + + const shadow = obj.clone() + + shadow.userData = { + isShadow: true, + entityId: obj.userData.entityId, + originPosition: obj.position.clone() // 保存原始位置 + } + this.dragShadows.add(shadow) + } + this.viewport.scene.add(this.dragShadows) + } + + /** + * 移除阴影 + */ + private removeShadows(): void { + if (this.dragShadows) { + this.viewport.scene.remove(this.dragShadows) + this.dragShadows = null + } + } + + /** + * 更新阴影位置(仅 X/Z 平面) + */ + private updateShadows(newPosition: THREE.Vector2): void { + if (!this.dragShadows) return + + // 计算新位置与拖拽开始位置的偏移量 + const offsetX = newPosition.x - this.dragStartMouse.x + const offsetZ = newPosition.y - this.dragStartMouse.y + + this.dragShadows.children.forEach((shadow, index) => { + const newPosX = shadow.userData.originPosition.x + offsetX + const newPosZ = shadow.userData.originPosition.z + offsetZ + + shadow.position.set(newPosX, shadow.userData.originPosition.y, newPosZ) // 锁定 Y 轴高度 + console.log(`Updated shadow position for ${shadow.name}:`, shadow.position) + }) + } + + private dragComplete = (startPos: THREE.Vector2, targetPos: THREE.Vector2): void => { + // console.log(`Drag completed from ${startPos.toArray()} to ${targetPos.toArray()}`) + this.viewport.stateManager.beginStateUpdate() + for (const object of this.dragShadows.children) { + const entityId = object.userData.entityId + if (entityId) { + const entity = this.viewport.stateManager.findItemById(entityId) + if (entity) { + // 更新实体位置 + entity.tf[0][0] = object.position.x + entity.tf[0][2] = object.position.z + + } else { + system.showErrorDialog('not found entityId:' + entityId) + } + } else { + system.showErrorDialog('not found entity') + } + } + this.viewport.stateManager.endStateUpdate() + EventBus.dispatch('multiselectedObjectChanged', { + multiSelectedObjects: this.viewport.state.multiSelectedObjects + }) + EventBus.dispatch('selectedObjectPropertyChanged', {}) + + this.cleanupDrag() + } + + /** + * pointermove 事件处理 + */ + private onPointerMove = (event: PointerEvent): void => { + if (!this.enabled) return + + if (!isNaN(this.dragStartMouse.x) && !isNaN(this.dragStartMouse.y) && this.dragShadows) { + this.isDragging = true + // 更新鼠标样式 + this.viewport.renderer.domElement.style.cursor = 'grabbing' + + // 更新阴影位置(锁定 Y 轴) + this.updateShadows(new THREE.Vector2(CurrentMouseInfo.x, CurrentMouseInfo.z)) + + } else { + + const mouse = this.getMousePosition(event.clientX, event.clientY) + const intersected = this.getIntersectedDraggableObject(mouse) + if (intersected) { + this.viewport.renderer.domElement.style.cursor = 'grab' + } else { + this.viewport.renderer.domElement.style.cursor = 'auto' + } + } + } + + /** + * pointerdown 事件处理 + */ + private onPointerDown = (event: PointerEvent): void => { + if (!this.enabled) return + + const mouse = this.getMousePosition(event.clientX, event.clientY) + const intersected = this.getIntersectedDraggableObject(mouse) + + if (!intersected) return + + this.isPointerDown = true + this.dragStartMouse.set(intersected.position.x, intersected.position.z) + this.viewport.controls.enabled = false + + let selectedObjects = [intersected] + if (this.viewport.state.multiSelectedObjects.length > 0) { + if (this.viewport.state.multiSelectedObjects.includes(intersected)) { + // drag multi-selected objects + selectedObjects = this.viewport.state.multiSelectedObjects + } + } + + this.createShadows(selectedObjects) + } + + + /** + * pointerup 事件处理 + */ + private onPointerUp = (event: PointerEvent): void => { + if (!this.enabled) return + + this.dragStartMouse.set(NaN, NaN) + this.isPointerDown = false + // console.log('enable controls') + this.viewport.controls.enabled = true + + if (this.isDragging) { + const startPos = this.dragStartMouse + const targetPos = new THREE.Vector2(CurrentMouseInfo.x, CurrentMouseInfo.z) + + if (startPos && targetPos) { + this.dragComplete(startPos, targetPos) + } + } + } + + /** + * pointerleave 事件处理 + */ + private onPointerLeave = (_event: PointerEvent): void => { + if (!this.enabled) return + this.cleanupDrag() + } +} diff --git a/src/core/engine/Viewport.ts b/src/core/engine/Viewport.ts index 8928f32..58daa86 100644 --- a/src/core/engine/Viewport.ts +++ b/src/core/engine/Viewport.ts @@ -22,6 +22,7 @@ import StateManager from '@/core/manager/StateManager.ts' import EventBus from '@/runtime/EventBus.ts' import Constract from '@/core/Constract.ts' import type { IMeta } from '@/core/base/IMeta.ts' +import DragControl2 from '@/core/controls/EsDragControl2.ts' /** * 视窗对象 @@ -34,15 +35,17 @@ export default class Viewport { statsControls: Stats controls: OrbitControls raycaster: THREE.Raycaster - dragControl: any // EsDragControls + // dragControl: any // EsDragControls animationFrameId: any = null scene: SceneHelp selectInspect = new SelectInspect() mouseMoveInspect = new MouseMoveInspect() + dragControl = new DragControl2() tools: IControls[] = [ markRaw(this.selectInspect), - markRaw(this.mouseMoveInspect) + markRaw(this.mouseMoveInspect), + markRaw(this.dragControl) ] // 状态管理器 @@ -155,18 +158,9 @@ export default class Viewport { this.renderer = renderer - // 创建正交摄像机 - // this.initMode2DCamera() - this.watchList.push(watch(() => this.state.view3DMode, (newVal) => { - if (newVal === Constract.Mode3D) { - this.initMode3DCamera() - } else { - this.initMode2DCamera() - } - }, { immediate: true })) // 注册拖拽组件 - this.dragControl = new EsDragControls(this) + // this.dragControl = new EsDragControls(this) // 性能监控 const statsControls = new Stats() @@ -202,6 +196,16 @@ export default class Viewport { tool.init(this) } + // 创建正交摄像机 + // this.initMode2DCamera() + this.watchList.push(watch(() => this.state.view3DMode, (newVal) => { + if (newVal === Constract.Mode3D) { + this.initMode3DCamera() + } else { + this.initMode2DCamera() + } + }, { immediate: true })) + // 触发所有物品类型的 afterAddViewport 方法 _.forEach(getAllItemTypes(), (itemType: ItemTypeDefineOption) => { itemType.clazz.afterAddViewport(this) diff --git a/src/model/itemType/ItemType.ts b/src/model/itemType/ItemType.ts index ed1eb1a..220e07b 100644 --- a/src/model/itemType/ItemType.ts +++ b/src/model/itemType/ItemType.ts @@ -60,7 +60,7 @@ export default abstract class ItemType { * 添加到 viewport 后的回调 */ afterAddViewport(viewport: Viewport): void { - viewport.dragControl.setDragObjects(this.pointArray, 'push') + //viewport.dragControl.setDragObjects(this.pointArray, 'push') const toolbox = this.createToolbox(viewport) viewport.toolbox[this.name] = toolbox } @@ -74,4 +74,4 @@ export default abstract class ItemType { * EsDragControls 拖拽完成(放开鼠标)时的回调 */ abstract dragPointComplete(viewport: Viewport) -} \ No newline at end of file +} diff --git a/src/model/itemType/Toolbox.ts b/src/model/itemType/Toolbox.ts index caae638..fd9845e 100644 --- a/src/model/itemType/Toolbox.ts +++ b/src/model/itemType/Toolbox.ts @@ -290,7 +290,7 @@ export default abstract class Toolbox { this.addToScene(marker) // 把点加入拖拽控制器 - this.viewport.dragControl.setDragObjects([marker], 'push') + //this.viewport.dragControl.setDragObjects([marker], 'push') if (this.startPoint) { this.afterAddPoint(this.startPoint, marker) @@ -320,4 +320,4 @@ export default abstract class Toolbox { */ destory() { } -} \ No newline at end of file +} diff --git a/src/modules/gstore/GstoreRenderer.ts b/src/modules/gstore/GstoreRenderer.ts index 2f7ea83..d4265ed 100644 --- a/src/modules/gstore/GstoreRenderer.ts +++ b/src/modules/gstore/GstoreRenderer.ts @@ -41,7 +41,6 @@ export default class GstoreRenderer extends BaseRenderer { ) } - createLineBasic(start: ItemJson, end: ItemJson, type: LinkType): THREE.Object3D[] { throw new Error('not allow store line.') } @@ -50,6 +49,10 @@ export default class GstoreRenderer extends BaseRenderer { throw new Error('not allow store line.') } + createPointBasic(item: ItemJson, option?: RendererCudOption): THREE.Object3D[] { + throw new Error('not allow createPointBasic.') + } + createPoint(item: ItemJson, option?: RendererCudOption): THREE.Object3D[] { // 创建平面几何体 if (!item.dt.storeWidth || !item.dt.storeDepth) { @@ -59,7 +62,7 @@ export default class GstoreRenderer extends BaseRenderer { group.name = GstoreRenderer.POINT_NAME // 绘制背景矩形框 - const planeGeometry = new THREE.PlaneGeometry(item.dt.storeWidth, item.dt.storeDepth); + const planeGeometry = new THREE.PlaneGeometry(item.dt.storeWidth, item.dt.storeDepth) planeGeometry.rotateX(Math.PI / 2) const planeMaterial = new THREE.MeshBasicMaterial({ color: '#dee8ee', @@ -67,8 +70,8 @@ export default class GstoreRenderer extends BaseRenderer { opacity: 0.5, // 50%透明度 depthWrite: false, // 防止深度冲突 side: THREE.DoubleSide // 双面渲染:ml-citation{ref="5,8" data="citationList"} - }); - const planeMesh = new THREE.Mesh(planeGeometry, planeMaterial); + }) + const planeMesh = new THREE.Mesh(planeGeometry, planeMaterial) group.add(planeMesh) // 绘制边框 @@ -76,30 +79,32 @@ export default class GstoreRenderer extends BaseRenderer { const lineYLen = item.dt.storeDepth - this.defaultLineWidth const lineGeometry = new LineGeometry().setPositions([ - -(lineXLen/2),0,-(lineYLen/2), - lineXLen/2,0,-(lineYLen/2), - lineXLen/2,0,lineYLen/2, - -(lineXLen/2),0,lineYLen/2, - -(lineXLen/2),0,-(lineYLen/2) - ]); + -(lineXLen / 2), 0, -(lineYLen / 2), + lineXLen / 2, 0, -(lineYLen / 2), + lineXLen / 2, 0, lineYLen / 2, + -(lineXLen / 2), 0, lineYLen / 2, + -(lineXLen / 2), 0, -(lineYLen / 2) + ]) const lineMaterial = new LineMaterial({ color: '#038217', linewidth: this.defaultLineWidth, worldUnits: true, resolution: new THREE.Vector2(window.innerWidth, window.innerHeight), side: THREE.DoubleSide - }); + }) // - const line = new Line2(lineGeometry, lineMaterial); + const line = new Line2(lineGeometry, lineMaterial) group.add(line as THREE.Object3D) // 设置位置 group.position.set(item.tf[0][0], item.tf[0][1], item.tf[0][2]) + const points = [group] this.fillObjectUserDataFromItem(item, ...points) this.afterCreateOrUpdatePoint(item, option, points) this.tempViewport.entityManager.appendObject(item.id, points) this.appendToScene(...points) + return points } diff --git a/src/modules/measure/MeasureRenderer.ts b/src/modules/measure/MeasureRenderer.ts index b38683e..b591705 100644 --- a/src/modules/measure/MeasureRenderer.ts +++ b/src/modules/measure/MeasureRenderer.ts @@ -110,7 +110,7 @@ export default class MeasureRenderer extends BaseRenderer { } const dragObjects = objects.filter(obj => !!obj.userData.draggable) - this.tempViewport.dragControl.setDragObjects(dragObjects, 'push') + //this.tempViewport.dragControl.setDragObjects(dragObjects, 'push') this.group.add(...objects) } diff --git a/src/modules/way/WayRenderer.ts b/src/modules/way/WayRenderer.ts index 19caaf9..6a13268 100644 --- a/src/modules/way/WayRenderer.ts +++ b/src/modules/way/WayRenderer.ts @@ -177,7 +177,7 @@ export default class WayRenderer extends BaseRenderer { appendToScene(...objects: THREE.Object3D[]) { const dragObjects = objects.filter(obj => !!obj.userData.draggable) - this.tempViewport.dragControl.setDragObjects(dragObjects, 'push') + //this.tempViewport.dragControl.setDragObjects(dragObjects, 'push') // this.tempViewport.dragControl.setDragObjects(objects, 'remove') this.tempViewport?.scene.add(...objects) From 8333ea11f372a9742565485864a843548b4cd2cf Mon Sep 17 00:00:00 2001 From: luoyifan Date: Fri, 6 Jun 2025 17:30:10 +0800 Subject: [PATCH 3/4] =?UTF-8?q?EsDragControl2=20=E6=8B=96=E6=8B=BD?= =?UTF-8?q?=E7=AE=A1=E7=90=86=E5=99=A8=E5=AE=8C=E6=88=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/core/ModelUtils.ts | 19 ++++++++++-- src/core/controls/EsDragControl2.ts | 53 +++++++++++++++++++++------------- src/core/controls/SelectInspect.ts | 31 ++++++++++++++++++-- src/core/engine/Viewport.ts | 19 ++++++------ src/core/manager/InteractionManager.ts | 6 ++-- 5 files changed, 92 insertions(+), 36 deletions(-) diff --git a/src/core/ModelUtils.ts b/src/core/ModelUtils.ts index 297b984..7befdd4 100644 --- a/src/core/ModelUtils.ts +++ b/src/core/ModelUtils.ts @@ -191,7 +191,22 @@ export function escByKeyboard() { return } - viewport.interactionManager.exitInteraction() + if (viewport.interactionManager.currentTool) { + // 1.退出当前交互 + viewport.interactionManager.exitInteraction() + + } else if (viewport.dragControl.isDragging) { + // 2.取消拖拽 + viewport.dragControl.cancelDrag() + + } else if (viewport.state.multiSelectedEntityIds?.length > 0) { + // 3.取消多选 + viewport.selectInspect.cancelMultiSelect() + + } else if (viewport.state.selectedEntityId) { + // 4.取消单选 + viewport.selectInspect.cancelSelect() + } system.msg('操作已取消') } @@ -258,7 +273,7 @@ export function moveSelectedItem(direct: '↑' | '↓' | '←' | '→') { // 根据方向移动 switch (direct) { case '↑': - console.log('向上移动', item.tf[0][2],'-=', delta) + console.log('向上移动', item.tf[0][2], '-=', delta) item.tf[0][2] -= delta // 向上移动 break case '↓': diff --git a/src/core/controls/EsDragControl2.ts b/src/core/controls/EsDragControl2.ts index b69ea09..f727191 100644 --- a/src/core/controls/EsDragControl2.ts +++ b/src/core/controls/EsDragControl2.ts @@ -10,9 +10,9 @@ import EventBus from '@/runtime/EventBus.ts' */ export default class DragControl2 implements IControls { private viewport: Viewport - private enabled: boolean = true - - private isDragging: boolean = false + private _is_enabled: boolean = true + private domElement: HTMLElement + public isDragging: boolean = false private isPointerDown: boolean = false private dragStartMouse: THREE.Vector2 = new THREE.Vector2() @@ -28,47 +28,49 @@ export default class DragControl2 implements IControls { domElement.addEventListener('pointerleave', this.onPointerLeave) domElement.style.cursor = 'auto' + this.domElement = domElement } /** * 设置启用/禁用 */ - set enable(value: boolean) { - this.enabled = value + public set enabled(value: boolean) { + this._is_enabled = value if (!value) { this.cleanupDrag() } } - get enable(): boolean { - return this.enabled + public get enabled(): boolean { + return this._is_enabled } /** * 卸载资源 */ dispose(): void { - const domElement = this.viewport.renderer.domElement - domElement.removeEventListener('pointermove', this.onPointerMove) - domElement.removeEventListener('pointerdown', this.onPointerDown) - domElement.removeEventListener('pointerup', this.onPointerUp) - domElement.removeEventListener('pointerleave', this.onPointerLeave) + if (this.domElement) { + this.domElement.removeEventListener('pointermove', this.onPointerMove) + this.domElement.removeEventListener('pointerdown', this.onPointerDown) + this.domElement.removeEventListener('pointerup', this.onPointerUp) + this.domElement.removeEventListener('pointerleave', this.onPointerLeave) - this.cleanupDrag() - domElement.style.cursor = 'auto' + this.cleanupDrag() + this.domElement.style.cursor = 'auto' + this.viewport = null + } } /** * 清理拖拽状态 */ private cleanupDrag(): void { - if (this.isDragging || this.isPointerDown) { - this.isDragging = false - this.isPointerDown = false - this.dragStartMouse.set(NaN, NaN) - this.removeShadows() - } + this.viewport.renderer.domElement.style.cursor = 'auto' + this.isDragging = false + this.isPointerDown = false + this.dragStartMouse.set(NaN, NaN) + this.removeShadows() } /** @@ -262,4 +264,15 @@ export default class DragControl2 implements IControls { if (!this.enabled) return this.cleanupDrag() } + + /** + * 取消当前拖拽状态 + */ + cancelDrag(): void { + if (this.isDragging || this.isPointerDown) { + this.cleanupDrag() + this.viewport.renderer.domElement.style.cursor = 'auto' + this.viewport.controls.enabled = true + } + } } diff --git a/src/core/controls/SelectInspect.ts b/src/core/controls/SelectInspect.ts index cf74775..d2d85d2 100644 --- a/src/core/controls/SelectInspect.ts +++ b/src/core/controls/SelectInspect.ts @@ -351,7 +351,7 @@ export default class SelectInspect implements IControls { selectedObject: this.viewport.state.selectedObject, selectedItem: this.viewport.state.selectedItem, selectedEntityId: this.viewport.state.selectedEntityId, - selectedObjectSetter: this.viewport.state.selectedObjectSetter, + selectedObjectSetter: this.viewport.state.selectedObjectSetter }) } } else { @@ -365,7 +365,7 @@ export default class SelectInspect implements IControls { selectedObject: null, selectedItem: null, selectedEntityId: null, - selectedObjectSetter: null, + selectedObjectSetter: null }) } } @@ -421,4 +421,31 @@ export default class SelectInspect implements IControls { } + cancelMultiSelect() { + this.viewport.state.multiSelectedObjects = [] + this.viewport.state.multiSelectedItems = [] + this.viewport.state.multiSelectedEntityIds = [] + this.viewport.state.multiSelectedObjectMetas = [] + EventBus.dispatch('multiSelectedObjectsChanged', { + viewport: markRaw(this.viewport), + multiSelectedObjects: [], + multiSelectedItems: [], + multiSelectedEntityIds: [], + multiSelectedObjectMetas: [] + }) + } + + cancelSelect() { + this.viewport.state.selectedObject = null + this.viewport.state.selectedItem = null + this.viewport.state.selectedEntityId = null + this.viewport.state.selectedObjectSetter = null + EventBus.dispatch('selectedObjectChanged', { + viewport: markRaw(this.viewport), + selectedObject: null, + selectedItem: null, + selectedEntityId: null, + selectedObjectSetter: null + }) + } } diff --git a/src/core/engine/Viewport.ts b/src/core/engine/Viewport.ts index bfec5f4..b71292e 100644 --- a/src/core/engine/Viewport.ts +++ b/src/core/engine/Viewport.ts @@ -23,7 +23,7 @@ import EventBus from '@/runtime/EventBus.ts' import Constract from '@/core/Constract.ts' import type { IMeta } from '@/core/base/IMeta.ts' import DragControl2 from '@/core/controls/EsDragControl2.ts' -import type { PropertySetter } from "@/core/base/PropertyTypes.ts"; +import type { PropertySetter } from '@/core/base/PropertyTypes.ts' /** * 视窗对象 @@ -462,6 +462,15 @@ export default class Viewport { dispose() { this.state.isReady = false + if (this.tools) { + for (const tool of this.tools) { + if (tool.dispose) { + tool.dispose() + } + } + this.tools = [] + } + if (this.animationFrameId !== null) { cancelAnimationFrame(this.animationFrameId) this.animationFrameId = null @@ -476,14 +485,6 @@ export default class Viewport { this.watchList = [] } - if (this.tools) { - for (const tool of this.tools) { - if (tool.dispose) { - tool.dispose() - } - } - this.tools = [] - } if (this.resizeObserver) { this.resizeObserver.unobserve(this.viewerDom) diff --git a/src/core/manager/InteractionManager.ts b/src/core/manager/InteractionManager.ts index a846d21..b7991c8 100644 --- a/src/core/manager/InteractionManager.ts +++ b/src/core/manager/InteractionManager.ts @@ -53,7 +53,7 @@ export default class InteractionManager implements IControls { } this.viewport.state.cursorMode = 'normal' - this.viewport.dragControl.dragControls.enabled = true + this.viewport.dragControl.enabled = true this.viewport.viewerDom.style.cursor = '' this.option = undefined @@ -90,7 +90,7 @@ export default class InteractionManager implements IControls { // 初始化交互 this.currentTool = interaction - this.viewport.dragControl.dragControls.enabled = false + this.viewport.dragControl.enabled = false this.currentTool.start(this.viewport, this.option) @@ -103,4 +103,4 @@ export default class InteractionManager implements IControls { dispose(): void { this.exitInteraction() } -} \ No newline at end of file +} From 5945edd41ff7c802a96876851c67128e83f82bc5 Mon Sep 17 00:00:00 2001 From: luoyifan Date: Fri, 6 Jun 2025 17:32:17 +0800 Subject: [PATCH 4/4] =?UTF-8?q?EsDragControl2=20=E6=8B=96=E6=8B=BD?= =?UTF-8?q?=E7=AE=A1=E7=90=86=E5=99=A8=E5=AE=8C=E6=88=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/core/controls/EsDragControl2.ts | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/src/core/controls/EsDragControl2.ts b/src/core/controls/EsDragControl2.ts index f727191..0bce29a 100644 --- a/src/core/controls/EsDragControl2.ts +++ b/src/core/controls/EsDragControl2.ts @@ -66,18 +66,20 @@ export default class DragControl2 implements IControls { * 清理拖拽状态 */ private cleanupDrag(): void { - this.viewport.renderer.domElement.style.cursor = 'auto' - this.isDragging = false - this.isPointerDown = false - this.dragStartMouse.set(NaN, NaN) - this.removeShadows() + if (this.domElement) { + this.domElement.style.cursor = 'auto' + this.isDragging = false + this.isPointerDown = false + this.dragStartMouse.set(NaN, NaN) + this.removeShadows() + } } /** * 获取当前鼠标坐标(归一化设备坐标) */ private getMousePosition(clientX: number, clientY: number): THREE.Vector2 { - const rect = this.viewport.renderer.domElement.getBoundingClientRect() + const rect = this.domElement.getBoundingClientRect() return new THREE.Vector2( ((clientX - rect.left) / rect.width) * 2 - 1, ((clientY - rect.top) / rect.height) * -2 + 1 @@ -187,12 +189,12 @@ export default class DragControl2 implements IControls { * pointermove 事件处理 */ private onPointerMove = (event: PointerEvent): void => { - if (!this.enabled) return + if (!this.enabled || !this.domElement) return if (!isNaN(this.dragStartMouse.x) && !isNaN(this.dragStartMouse.y) && this.dragShadows) { this.isDragging = true // 更新鼠标样式 - this.viewport.renderer.domElement.style.cursor = 'grabbing' + this.domElement.style.cursor = 'grabbing' // 更新阴影位置(锁定 Y 轴) this.updateShadows(new THREE.Vector2(CurrentMouseInfo.x, CurrentMouseInfo.z)) @@ -202,9 +204,9 @@ export default class DragControl2 implements IControls { const mouse = this.getMousePosition(event.clientX, event.clientY) const intersected = this.getIntersectedDraggableObject(mouse) if (intersected) { - this.viewport.renderer.domElement.style.cursor = 'grab' + this.domElement.style.cursor = 'grab' } else { - this.viewport.renderer.domElement.style.cursor = 'auto' + this.domElement.style.cursor = 'auto' } } } @@ -269,9 +271,10 @@ export default class DragControl2 implements IControls { * 取消当前拖拽状态 */ cancelDrag(): void { + if (!this.domElement) return if (this.isDragging || this.isPointerDown) { this.cleanupDrag() - this.viewport.renderer.domElement.style.cursor = 'auto' + this.domElement.style.cursor = 'auto' this.viewport.controls.enabled = true } }