Browse Source

编码重新做

master
修宁 6 months ago
parent
commit
a66d103107
  1. 21
      package.json
  2. 13
      pnpm-lock.yaml
  3. 4
      src/core/Constract.ts
  4. 7
      src/core/base/BaseRenderer.ts
  5. 16
      src/core/engine/SceneHelp.ts
  6. 1
      src/core/manager/EntityManager.ts
  7. 36
      src/core/manager/LabelManager.ts
  8. 182
      src/example/example1.js
  9. 20
      src/modules/gstore/GstoreRenderer.ts
  10. 33
      src/modules/rack/RackRenderer.ts
  11. 105
      src/modules/way/WayRenderer.ts
  12. 10
      src/types/model.d.ts

21
package.json

@ -13,26 +13,27 @@
"format": "prettier --write src/" "format": "prettier --write src/"
}, },
"dependencies": { "dependencies": {
"@vueuse/core": "^13.2.0" "@vueuse/core": "^13.2.0",
"fdir": "^6.4.6"
}, },
"devDependencies": { "devDependencies": {
"@ease-forge/runtime": "^1.0.12", "@ease-forge/runtime": "^1.0.12",
"@ease-forge/shared": "^1.0.12", "@ease-forge/shared": "^1.0.12",
"@element-plus/icons-vue": "^2.3.1", "@element-plus/icons-vue": "^2.3.1",
"@guolao/vue-monaco-editor": "^1.5.5",
"@rolldown/pluginutils": "1.0.0-beta.8-commit.56abf23", "@rolldown/pluginutils": "1.0.0-beta.8-commit.56abf23",
"@tsconfig/node22": "^22.0.1", "@tsconfig/node22": "^22.0.1",
"@types/codemirror": "^5.60.16",
"@types/jquery": "^3.3.31", "@types/jquery": "^3.3.31",
"@types/lodash": "^4.17.7", "@types/lodash": "^4.17.7",
"@types/node": "^22.14.0", "@types/node": "^22.14.0",
"@types/three": "^0.176.0", "@types/three": "^0.176.0",
"@types/codemirror": "^5.60.16", "@typescript/vfs": "^1.6.1",
"@vicons/antd": "^0.13.0", "@vicons/antd": "^0.13.0",
"@vicons/fa": "^0.12.0", "@vicons/fa": "^0.12.0",
"@vitejs/plugin-vue": "^5.2.3", "@vitejs/plugin-vue": "^5.2.3",
"@vitejs/plugin-vue-jsx": "^4.2.0", "@vitejs/plugin-vue-jsx": "^4.2.0",
"@vue/tsconfig": "^0.7.0", "@vue/tsconfig": "^0.7.0",
"@typescript/vfs": "^1.6.1",
"rollup-plugin-typescript2": "^0.36.0",
"ag-grid-community": "^28.2.1", "ag-grid-community": "^28.2.1",
"ag-grid-enterprise": "^28.2.1", "ag-grid-enterprise": "^28.2.1",
"ag-grid-vue3": "^28.2.1", "ag-grid-vue3": "^28.2.1",
@ -42,6 +43,7 @@
"dat.gui": "^0.7.9", "dat.gui": "^0.7.9",
"decimal.js": "^10.5.0", "decimal.js": "^10.5.0",
"element-plus": "^2.9.10", "element-plus": "^2.9.10",
"gsap": "^3.13.0",
"hotkeys-js": "^3.13.10", "hotkeys-js": "^3.13.10",
"jquery": "^3.6.0", "jquery": "^3.6.0",
"json5": "^2.2.3", "json5": "^2.2.3",
@ -53,23 +55,22 @@
"pinia": "^3.0.1", "pinia": "^3.0.1",
"prettier": "3.5.3", "prettier": "3.5.3",
"rimraf": "^6.0.1", "rimraf": "^6.0.1",
"rollup-plugin-typescript2": "^0.36.0",
"sortablejs": "1.15.6", "sortablejs": "1.15.6",
"split.js": "^1.6.4", "split.js": "^1.6.4",
"three": "^0.177.0", "three": "^0.177.0",
"three-csg-ts": "^3.2.0",
"three-dxf-viewer": "^1.0.36",
"three-mesh-bvh": "^0.9.0",
"troika-three-text": "^0.52.4", "troika-three-text": "^0.52.4",
"tslib": "2.8.1", "tslib": "2.8.1",
"typescript": "~5.8.0", "typescript": "~5.8.0",
"vite": "^6.2.4", "vite": "^6.2.4",
"vite-plugin-vue-devtools": "^7.7.2", "vite-plugin-vue-devtools": "^7.7.2",
"vue": "^3.5.13", "vue": "^3.5.13",
"@guolao/vue-monaco-editor": "^1.5.5",
"vue-i18n": "9.2.2", "vue-i18n": "9.2.2",
"vue-router": "^4.5.0", "vue-router": "^4.5.0",
"vue-tsc": "^2.2.8", "vue-tsc": "^2.2.8",
"vue3-menus": "^1.1.2", "vue3-menus": "^1.1.2"
"three-mesh-bvh": "^0.9.0",
"three-dxf-viewer": "^1.0.36",
"gsap": "^3.13.0",
"three-csg-ts": "^3.2.0"
} }
} }

13
pnpm-lock.yaml

@ -11,6 +11,9 @@ importers:
'@vueuse/core': '@vueuse/core':
specifier: ^13.2.0 specifier: ^13.2.0
version: 13.2.0(vue@3.5.14(typescript@5.8.3)) version: 13.2.0(vue@3.5.14(typescript@5.8.3))
fdir:
specifier: ^6.4.6
version: 6.4.6(picomatch@4.0.2)
devDependencies: devDependencies:
'@ease-forge/runtime': '@ease-forge/runtime':
specifier: ^1.0.12 specifier: ^1.0.12
@ -1121,8 +1124,8 @@ packages:
resolution: {integrity: sha512-QFNnTvU3UjgWFy8Ef9iDHvIdcgZ344ebkwYx4/KLbR+CKQA4xBaHzv+iRpp86QfMHP8faFQLh8iOc57215y4Rg==} resolution: {integrity: sha512-QFNnTvU3UjgWFy8Ef9iDHvIdcgZ344ebkwYx4/KLbR+CKQA4xBaHzv+iRpp86QfMHP8faFQLh8iOc57215y4Rg==}
engines: {node: ^18.19.0 || >=20.5.0} engines: {node: ^18.19.0 || >=20.5.0}
fdir@6.4.4: fdir@6.4.6:
resolution: {integrity: sha512-1NZP+GK4GfuAv3PqKvxQRDMjdSRZjnkq7KfhlNrCNNlZ0ygQFpebfrnfnq/W7fpUnAv9aGWmY1zKx7FYL3gwhg==} resolution: {integrity: sha512-hiFoqpyZcfNm1yc4u8oWCf9A2c4D3QjCrks3zmoVKVxpQRzmPNar1hUJcBG2RQHvEVGDN+Jm81ZheVLAQMK6+w==}
peerDependencies: peerDependencies:
picomatch: ^3 || ^4 picomatch: ^3 || ^4
peerDependenciesMeta: peerDependenciesMeta:
@ -2936,7 +2939,7 @@ snapshots:
strip-final-newline: 4.0.0 strip-final-newline: 4.0.0
yoctocolors: 2.1.1 yoctocolors: 2.1.1
fdir@6.4.4(picomatch@4.0.2): fdir@6.4.6(picomatch@4.0.2):
optionalDependencies: optionalDependencies:
picomatch: 4.0.2 picomatch: 4.0.2
@ -3485,7 +3488,7 @@ snapshots:
tinyglobby@0.2.13: tinyglobby@0.2.13:
dependencies: dependencies:
fdir: 6.4.4(picomatch@4.0.2) fdir: 6.4.6(picomatch@4.0.2)
picomatch: 4.0.2 picomatch: 4.0.2
totalist@3.0.1: {} totalist@3.0.1: {}
@ -3576,7 +3579,7 @@ snapshots:
vite@6.3.5(@types/node@22.15.21)(less@4.3.0): vite@6.3.5(@types/node@22.15.21)(less@4.3.0):
dependencies: dependencies:
esbuild: 0.25.4 esbuild: 0.25.4
fdir: 6.4.4(picomatch@4.0.2) fdir: 6.4.6(picomatch@4.0.2)
picomatch: 4.0.2 picomatch: 4.0.2
postcss: 8.5.3 postcss: 8.5.3
rollup: 4.41.0 rollup: 4.41.0

4
src/core/Constract.ts

@ -34,6 +34,8 @@ const Constract = Object.freeze({
HEIGHT_WAY_LINE: 0.02, HEIGHT_WAY_LINE: 0.02,
// 鼠标点击延迟 // 鼠标点击延迟
MOUSE_CLICK_DELAY: 200 MOUSE_CLICK_DELAY: 200,
WAY_ID_LABEL: 'way_id_label',
}) })
export default Constract export default Constract

7
src/core/base/BaseRenderer.ts

@ -58,7 +58,7 @@ export default abstract class BaseRenderer {
/** /**
* 线 * 线
*/ */
createLineBasic(start: ItemJson, end: ItemJson, type: LinkType): LineLike { createLineBasic(start: ItemJson, end: ItemJson, type: LinkType): LineLike | undefined | void {
throw new Error('createLineBasic method must be implemented in derived class.') throw new Error('createLineBasic method must be implemented in derived class.')
} }
@ -155,7 +155,7 @@ export default abstract class BaseRenderer {
if (!rackRenderer) { if (!rackRenderer) {
console.error(`Cannot find renderer for rack type ${rack.t}`) console.error(`Cannot find renderer for rack type ${rack.t}`)
} }
const { position, rotation } = rackRenderer.getStorePlacement(this.tempViewport, item) const { position, rotation } = rackRenderer.getStorePlacement(rack, item.dt.storeAt.bay, item.dt.storeAt.level, item.dt.storeAt.cell)
if (!position || !rotation) { if (!position || !rotation) {
console.error(`无法获取物品 ${item.id} 的存储位置`) console.error(`无法获取物品 ${item.id} 的存储位置`)
} }
@ -291,7 +291,6 @@ export default abstract class BaseRenderer {
this.tempViewport.entityManager.appendLineObject(id, line) this.tempViewport.entityManager.appendLineObject(id, line)
if (line instanceof THREE.Object3D) { if (line instanceof THREE.Object3D) {
this.appendToScene(line) this.appendToScene(line)
} }
this.afterCreateOrUpdateLine(start, end, type, option, line) this.afterCreateOrUpdateLine(start, end, type, option, line)
@ -312,7 +311,7 @@ export default abstract class BaseRenderer {
* *
* Position Rotation * Position Rotation
*/ */
getStorePlacement(viewport: Viewport, item: ItemJson) getStorePlacement(storeItem: ItemJson, bay = 0, level = 0, cell = 0)
: { position: [number, number, number], rotation: [number, number, number] } { : { position: [number, number, number], rotation: [number, number, number] } {
throw new Error(' 不支持库存物品的添加. t=' + this.itemTypeName) throw new Error(' 不支持库存物品的添加. t=' + this.itemTypeName)
} }

16
src/core/engine/SceneHelp.ts

@ -81,14 +81,14 @@ export default class SceneHelp {
this.scene.add(hemisphereLight) this.scene.add(hemisphereLight)
// 完全不透明的地板 // 完全不透明的地板
const geometry = new THREE.PlaneGeometry(gridOption.gridSize, gridOption.gridSize) // const geometry = new THREE.PlaneGeometry(gridOption.gridSize, gridOption.gridSize)
const material = new THREE.MeshBasicMaterial({ // const material = new THREE.MeshBasicMaterial({
color: '#ffffff', // color: '#ffffff',
side: THREE.BackSide // side: THREE.BackSide
}) // })
const ground = new THREE.Mesh(geometry, material) // const ground = new THREE.Mesh(geometry, material)
ground.rotation.x = -Math.PI / 2 // ground.rotation.x = -Math.PI / 2
this.scene.add(ground) // this.scene.add(ground)
// const directionalLight = new THREE.DirectionalLight(0xffffff, 1.5) // const directionalLight = new THREE.DirectionalLight(0xffffff, 1.5)
// directionalLight.position.set(5, 5, 5).multiplyScalar(3) // directionalLight.position.set(5, 5, 5).multiplyScalar(3)

1
src/core/manager/EntityManager.ts

@ -219,6 +219,7 @@ export default class EntityManager {
if (start.t !== itemTypeName) { if (start.t !== itemTypeName) {
// 只通知起点对应的渲染器 // 只通知起点对应的渲染器
// console.log(`[create] ${start.id} -> ${end.id} [${lineDiffItem.type}] => ${lineId}, 但起点类型不匹配, 跳过`)
continue continue
} }
renderer.createLine(start, end, lineDiffItem.type) renderer.createLine(start, end, lineDiffItem.type)

36
src/core/manager/LabelManager.ts

@ -43,6 +43,40 @@ export default class LabelManager {
return labelObj return labelObj
} }
createOrUpdateMeshLabel(parentObj: Object3DLike, text: string, option: LabelOption) {
let labelObj = this.labelMap.get(parentObj.userData.labelObjectId)
if (!labelObj) {
labelObj = this.createLabelObject(option)
parentObj.userData.meshLabelObjectId = labelObj.uuid
this.labelGroup.add(labelObj)
}
if (labelObj) {
const matrix: THREE.Matrix4 = parentObj.matrix
const pos = new THREE.Vector3()
matrix.decompose(pos, new THREE.Quaternion(), new THREE.Vector3())
if (option.offset) {
if (option.offset instanceof THREE.Vector3) {
pos.add(option.offset)
} else if (Array.isArray(option.offset)) {
pos.add(new THREE.Vector3(...option.offset))
}
}
labelObj.position.copy(pos)
if (labelObj instanceof CSS2DObject) {
labelObj.element.innerHTML = text
} else if (labelObj instanceof Text) {
labelObj.text = text
labelObj.quaternion.copy(this.viewport.camera.quaternion)
labelObj.sync()
}
}
return labelObj
}
createLabel(parentObj: Object3DLike | LineLike, option: LabelOption): Text | CSS2DObject { createLabel(parentObj: Object3DLike | LineLike, option: LabelOption): Text | CSS2DObject {
const labelObj = this.createLabelObject(option) const labelObj = this.createLabelObject(option)
parentObj.userData.labelObjectId = labelObj.uuid parentObj.userData.labelObjectId = labelObj.uuid
@ -215,6 +249,8 @@ export interface LabelOption {
* ex: css='5px 8px', text=0.2 * ex: css='5px 8px', text=0.2
*/ */
padding?: number | string padding?: number | string
offset?: THREE.Vector3 | [number, number, number]
text?: string text?: string
format?: (distance: number) => string format?: (distance: number) => string

182
src/example/example1.js

@ -207,124 +207,164 @@ export default {
dt: { in: [], out: [], center: ['3cdb6OHkp132soSsgW8McA', '3ExXFSuV9WB2WMY2Quyq6L'] } dt: { in: [], out: [], center: ['3cdb6OHkp132soSsgW8McA', '3ExXFSuV9WB2WMY2Quyq6L'] }
}, },
{ {
id: '6Vu3dX1V7Si0ISWIiCkoEh', t: 'gstore', v: true, strokeWidth: 0.1, id: '1', t: 'way', v: true,
tf: [[1.5, 0, 0.63], [0, 90, 0], [1, 0, 1]],
dt: { in: [], out: [], center: [], storeWidth: 1.1 }
},
{
id: '592UY0EMScbwIyQqgs8aAs', t: 'gstore', v: true, strokeWidth: 0.1,
tf: [[3.9, 0, 0.63], [0, 90, 0], [1, 0, 1]],
dt: { in: [], out: [], center: [] }
},
{
id: '38TYyVWMGLf8OogQMIiSOz', t: 'gstore', v: true, strokeWidth: 0.1,
tf: [[7.1, 0, 2.865], [0, 0, 0], [1, 0, 1]],
dt: { in: [], out: [], center: [] }
},
{
id: '1hAaZ1xtvukZowAKeWAcqs', t: 'gstore', v: true, strokeWidth: 0.1,
tf: [[7.1, 0, 4.35], [0, 0, 0], [1, 0, 1]],
dt: { in: [], out: [], center: [] }
},
{
id: '28GxDYUqDwZc2WsOgMU2wi', t: 'gstore', v: true, strokeWidth: 0.1,
tf: [[7.1, 0, 6.75], [0, 90, 0], [1, 0, 1]],
dt: { in: [], out: [], center: [] }
},
{
id: '2fWOnUmFpvYyCWEqAyU0QC', t: 'way', v: true,
tf: [[1.5, 0, 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, 2.13], [90, 0, 0], [0.25, 0.25, 0.1]], tf: [[2.7, 0, 2.13], [90, 0, 0], [0.25, 0.25, 0.1]],
dt: { in: [], out: [], center: ['2fWOnUmFpvYyCWEqAyU0QC', '2CSDVrpqthaiQuyWUymCwy', '0mVU9FacN1fmCAmQqwWgIZ'] } dt: { in: [], out: [], center: ['38', '36', '2'], autogyration: true }
},
{
id: '2CSDVrpqthaiQuyWUymCwy', t: 'way', v: true,
tf: [[3.9, 0, 2.13], [90, 0, 0], [0.25, 0.25, 0.1]],
dt: { in: [], out: [], center: ['09PTEMUnACWY0MUG4qmk0r'] }
}, },
{ {
id: '0mVU9FacN1fmCAmQqwWgIZ', t: 'way', v: true, id: '2', t: 'way', v: true,
tf: [[2.7, 0, 2.832], [90, 0, 0], [0.25, 0.25, 0.1]], tf: [[2.7, 0, 2.832], [90, 0, 0], [0.25, 0.25, 0.1]],
dt: { in: [], out: [], center: ['09PTEMUnACWY0MUG4qmk0r', '7LuzEYQQI7OQcEUekEqWcm'] } dt: { in: [], out: [], center: ['1', '3'] }
}, },
{ {
id: '7LuzEYQQI7OQcEUekEqWcm', t: 'way', v: true, id: '3', t: 'way', v: true,
tf: [[2.7, 0, 3.932], [90, 0, 0], [0.25, 0.25, 0.1]], tf: [[2.7, 0, 3.932], [90, 0, 0], [0.25, 0.25, 0.1]],
dt: { in: [], out: [], center: ['0mVU9FacN1fmCAmQqwWgIZ', '2RForJhOHXtcw0gq8mYAMh'] } dt: {
in: [], out: [], center: ['2', '4'],
linkStoreAt: { item: 'rack1', bay: 3, level: 2, cell: 0 }
}
}, },
{ {
id: '2RForJhOHXtcw0gq8mYAMh', t: 'way', v: true, id: '4', t: 'way', v: true,
tf: [[2.7, 0, 4.582], [90, 0, 0], [0.25, 0.25, 0.1]], tf: [[2.7, 0, 4.582], [90, 0, 0], [0.25, 0.25, 0.1]],
dt: { in: [], out: [], center: ['7LuzEYQQI7OQcEUekEqWcm', '32vDSCKBrgMWycW0ySIgsJ'] } dt: { in: [], out: [], center: ['3', '5'] }
}, },
{ {
id: '32vDSCKBrgMWycW0ySIgsJ', t: 'way', v: true, id: '5', t: 'way', v: true,
tf: [[2.7, 0, 5.232], [90, 0, 0], [0.25, 0.25, 0.1]], tf: [[2.7, 0, 5.232], [90, 0, 0], [0.25, 0.25, 0.1]],
dt: { in: [], out: [], center: ['2RForJhOHXtcw0gq8mYAMh', '0wcYKcGQialFQCGkAa6aYB'] } dt: {
in: [], out: [], center: ['4', '6'],
linkStoreAt: { item: 'rack1', bay: 2, level: 2, cell: 0 }
}
}, },
{ {
id: '0wcYKcGQialFQCGkAa6aYB', t: 'way', v: true, id: '6', t: 'way', v: true,
tf: [[2.7, 0, 5.882], [90, 0, 0], [0.25, 0.25, 0.1]], tf: [[2.7, 0, 5.882], [90, 0, 0], [0.25, 0.25, 0.1]],
dt: { in: [], out: [], center: ['32vDSCKBrgMWycW0ySIgsJ', '55g6mUWBdozg4m2ueUEUsy'] } dt: { in: [], out: [], center: ['5', '7'] }
}, },
{ {
id: '55g6mUWBdozg4m2ueUEUsy', t: 'way', v: true, id: '7', t: 'way', v: true,
tf: [[2.7, 0, 6.532], [90, 0, 0], [0.25, 0.25, 0.1]], tf: [[2.7, 0, 6.532], [90, 0, 0], [0.25, 0.25, 0.1]],
dt: { in: [], out: [], center: ['0wcYKcGQialFQCGkAa6aYB', '5iKoIUBhnU08EM0IsoyOSW'] } dt: {
in: [], out: [], center: ['6', '8'],
linkStoreAt: { item: 'rack1', bay: 1, level: 1, cell: 0 }
}
}, },
{ {
id: '5iKoIUBhnU08EM0IsoyOSW', t: 'way', v: true, id: '8', t: 'way', v: true,
tf: [[2.7, 0, 7.75], [90, 0, 0], [0.25, 0.25, 0.1]], tf: [[2.7, 0, 7.75], [90, 0, 0], [0.25, 0.25, 0.1]],
dt: { in: [], out: [], center: ['55g6mUWBdozg4m2ueUEUsy'] } dt: {
in: [], out: [], center: ['7'],
linkStoreAt: { item: 'rack1', bay: 0, level: 2, cell: 0 }
}
}, },
{ {
id: '3ZP01pHXJRuyeg24oCaaMq', t: 'way', v: true, id: '17', t: 'way', v: true,
tf: [[5.65, 0, 2.13], [90, 0, 0], [0.25, 0.25, 0.1]], tf: [[5.65, 0, 2.13], [90, 0, 0], [0.25, 0.25, 0.1]],
dt: { in: [], out: [], center: ['5onDSGuIKBpUQo6g0EIsuS'] } dt: { in: [], out: [], center: ['20'] }
}, },
{ {
id: '5onDSGuIKBpUQo6g0EIsuS', t: 'way', v: true, id: '20', t: 'way', v: true,
tf: [[5.65, 0, 2.865], [90, 0, 0], [0.25, 0.25, 0.1]], tf: [[5.65, 0, 2.865], [90, 0, 0], [0.25, 0.25, 0.1]],
dt: { in: [], out: [], center: ['3ZP01pHXJRuyeg24oCaaMq', '41A0CKR8cFW8wKkcSMQ4uk'] } dt: {
in: [], out: [], center: ['17', '21'],
linkStoreAt: { item: '54', bay: 0, level: 0, cell: 0 }
}
}, },
{ {
id: '41A0CKR8cFW8wKkcSMQ4uk', t: 'way', v: true, id: '21', t: 'way', v: true,
tf: [[5.65, 0, 3.932], [90, 0, 0], [0.25, 0.25, 0.1]], tf: [[5.65, 0, 3.932], [90, 0, 0], [0.25, 0.25, 0.1]],
dt: { in: [], out: [], center: ['5onDSGuIKBpUQo6g0EIsuS', '4PunEz5C3Xk66EaOgMEuMq'] } dt: {
in: [], out: [], center: ['20', '22'],
linkStoreAt: { item: 'rack1', bay: 3, level: 1, cell: 0 }
}
}, },
{ {
id: '4PunEz5C3Xk66EaOgMEuMq', t: 'way', v: true, id: '22', t: 'way', v: true,
tf: [[5.65, 0, 4.348], [90, 0, 0], [0.25, 0.25, 0.1]], tf: [[5.65, 0, 4.348], [90, 0, 0], [0.25, 0.25, 0.1]],
dt: { in: [], out: [], center: ['41A0CKR8cFW8wKkcSMQ4uk', '6oCW8i0dpRtuCEIWIaAcQi'] } dt: {
in: [], out: [], center: ['21', '23'],
linkStoreAt: { item: '56', bay: 0, level: 0, cell: 0 }
}
}, },
{ {
id: '6oCW8i0dpRtuCEIWIaAcQi', t: 'way', v: true, id: '23', t: 'way', v: true,
tf: [[5.65, 0, 5.232], [90, 0, 0], [0.25, 0.25, 0.1]], tf: [[5.65, 0, 5.232], [90, 0, 0], [0.25, 0.25, 0.1]],
dt: { in: [], out: [], center: ['4PunEz5C3Xk66EaOgMEuMq', '3C9Z8c6oxQbWcS4uSGkC8b'] } dt: {
in: [], out: [], center: ['22', '24'], autogyration: true,
linkStoreAt: { item: 'rack1', bay: 2, level: 1, cell: 0 }
}
}, },
{ {
id: '3C9Z8c6oxQbWcS4uSGkC8b', t: 'way', v: true, id: '24', t: 'way', v: true,
tf: [[5.65, 0, 5.882], [90, 0, 0], [0.25, 0.25, 0.1]], tf: [[5.65, 0, 5.882], [90, 0, 0], [0.25, 0.25, 0.1]],
dt: { in: [], out: [], center: ['6oCW8i0dpRtuCEIWIaAcQi', '1jJX8KZLMPSSCwuCOU6AQz'] } dt: { in: [], out: [], center: ['23', '25'] }
}, },
{ {
id: '1jJX8KZLMPSSCwuCOU6AQz', t: 'way', v: true, id: '25', t: 'way', v: true,
tf: [[5.65, 0, 6.532], [90, 0, 0], [0.25, 0.25, 0.1]], tf: [[5.65, 0, 6.532], [90, 0, 0], [0.25, 0.25, 0.1]],
dt: { in: [], out: [], center: ['3C9Z8c6oxQbWcS4uSGkC8b', '0aJ81sOKqm9FYo60AIQmMG'] } dt: {
in: [], out: [], center: ['24', '26'],
linkStoreAt: { item: 'rack1', bay: 1, level: 1, cell: 0 }
}
}, },
{ {
id: '0aJ81sOKqm9FYo60AIQmMG', t: 'way', v: true, id: '26', t: 'way', v: true,
tf: [[5.65, 0, 6.744], [90, 0, 0], [0.25, 0.25, 0.1]], tf: [[5.65, 0, 6.744], [90, 0, 0], [0.25, 0.25, 0.1]],
dt: { in: [], out: [], center: ['1jJX8KZLMPSSCwuCOU6AQz', '2qtxSDVn30EcI2uY4W0CWf'] } dt: {
in: [], out: [], center: ['25', '27'],
linkStoreAt: { item: '58', bay: 0, level: 0, cell: 0 }
}
}, },
{ {
id: '2qtxSDVn30EcI2uY4W0CWf', t: 'way', v: true, id: '27', t: 'way', v: true,
tf: [[5.65, 0, 7.75], [90, 0, 0], [0.25, 0.25, 0.1]], tf: [[5.65, 0, 7.75], [90, 0, 0], [0.25, 0.25, 0.1]],
dt: { in: [], out: [], center: ['0aJ81sOKqm9FYo60AIQmMG'] } dt: {
in: [], out: [], center: ['26'],
linkStoreAt: { item: 'rack1', bay: 0, level: 1, cell: 0 }
}
},
{
id: '36', t: 'way', v: true,
tf: [[3.9, 0, 2.13], [90, 0, 0], [0.25, 0.25, 0.1]],
dt: {
in: [], out: [], center: ['1'],
linkStoreAt: { item: '47', bay: 0, level: 0, cell: 0 }
}
},
{
id: '38', t: 'way', v: true,
tf: [[1.5, 0, 2.13], [90, 0, 0], [0.25, 0.25, 0.1]],
dt: {
in: [], out: [], center: ['1'],
linkStoreAt: { item: '49', bay: 0, level: 0, cell: 0 }
}
},
{
id: '47', t: 'gstore', v: true,
tf: [[3.9, 0, 0.63], [0, 90, 0], [1, 0.01, 1]],
dt: { in: [], out: [], center: [], strokeWidth: 0.1 }
},
{
id: '49', t: 'gstore', v: true,
tf: [[1.5, 0, 0.63], [0, 90, 0], [1, 0.01, 1]],
dt: { in: [], out: [], center: [], strokeWidth: 0.1 }
},
{
id: '54', t: 'gstore', v: true,
tf: [[7.1, 0, 2.865], [0, 0, 0], [1, 0.01, 1]],
dt: { in: [], out: [], center: [], strokeWidth: 0.1 }
},
{
id: '56', t: 'gstore', v: true,
tf: [[7.1, 0, 4.35], [0, 0, 0], [1, 0.01, 1]],
dt: { in: [], out: [], center: [], strokeWidth: 0.1 }
},
{
id: '58', t: 'gstore', v: true,
tf: [[7.1, 0, 6.75], [0, 90, 0], [1, 0.01, 1]],
dt: { in: [], out: [], center: [], strokeWidth: 0.1 }
}, },
{ {
id: 'ptr1', t: 'cl2', v: true, id: 'ptr1', t: 'cl2', v: true,
@ -354,7 +394,7 @@ export default {
dt: { dt: {
in: [], out: [], center: [], in: [], out: [], center: [],
storeAt: { // 存储位置 storeAt: { // 存储位置
item: '6Vu3dX1V7Si0ISWIiCkoEh', // 库存容器ID item: '49', // 库存容器ID
bay: 0, // 列 bay: 0, // 列
level: 0, // 层 level: 0, // 层
cell: 0 // 格 cell: 0 // 格
@ -368,7 +408,7 @@ export default {
tf: [[0, 0, 0], [0, 0, 0], [1.2, 0.15, 1]], tf: [[0, 0, 0], [0, 0, 0], [1.2, 0.15, 1]],
dt: { dt: {
in: [], out: [], center: [], in: [], out: [], center: [],
storeAt: { item: '38TYyVWMGLf8OogQMIiSOz', bay: 0, level: 0, cell: 0 } storeAt: { item: '54', bay: 0, level: 0, cell: 0 }
} }
}, },
{ {

20
src/modules/gstore/GstoreRenderer.ts

@ -51,12 +51,16 @@ export default class GstoreRenderer extends BaseRenderer {
return this.pointManager.createByItem(item) return this.pointManager.createByItem(item)
} }
createLineBasic(start: ItemJson, end: ItemJson, type: LinkType): THREE.Object3D { createLine(start: ItemJson, end: ItemJson, type: LinkType, option?: RendererCudOption) {
throw new Error('not allow store line.') // throw new Error('not allow store line.')
}
createLineBasic(start: ItemJson, end: ItemJson, type: LinkType) {
// throw new Error('not allow store line.')
} }
updateLine(start: ItemJson, end: ItemJson, type: LinkType, option?: RendererCudOption) { updateLine(start: ItemJson, end: ItemJson, type: LinkType, option?: RendererCudOption) {
throw new Error('not allow store line.') // throw new Error('not allow store line.')
} }
/** /**
@ -168,15 +172,9 @@ export default class GstoreRenderer extends BaseRenderer {
* *
* Position Rotation * Position Rotation
*/ */
getStorePlacement(viewport: Viewport, item: ItemJson): { position: [number, number, number], rotation: [number, number, number] } { getStorePlacement(me: ItemJson, bay = 0, level = 0, cell = 0): { position: [number, number, number], rotation: [number, number, number] } {
if (!item.dt?.storeAt?.item) {
// 没有定义存储位置,返回空对象
//@ts-ignore
return {}
}
// 将这个物品添加到库存中 // 将这个物品添加到库存中
const me = viewport.entityManager.findItemById(item.dt.storeAt.item) // const me = viewport.entityManager.findItemById(item.dt.storeAt.item)
return { position: me.tf[0], rotation: me.tf[1] } return { position: me.tf[0], rotation: me.tf[1] }
} }
} }

33
src/modules/rack/RackRenderer.ts

@ -3,7 +3,7 @@ import BaseRenderer from '@/core/base/BaseRenderer.ts'
import { decimalSumBy } from '@/core/ModelUtils' import { decimalSumBy } from '@/core/ModelUtils'
import Constract from '@/core/Constract.ts' import Constract from '@/core/Constract.ts'
import type Viewport from '@/core/engine/Viewport.ts' import type Viewport from '@/core/engine/Viewport.ts'
import Rack3dObject from "@/modules/rack/Rack3dObject"; import Rack3dObject from '@/modules/rack/Rack3dObject'
/** /**
* *
@ -42,32 +42,35 @@ export default class RackRenderer extends BaseRenderer {
) )
} }
createLine(start: ItemJson, end: ItemJson, type: LinkType, option?: RendererCudOption) {
// throw new Error('not allow store line.')
}
createLineBasic(start: ItemJson, end: ItemJson, type: LinkType): THREE.Object3D { createLineBasic(start: ItemJson, end: ItemJson, type: LinkType) {
throw new Error('not allow store line.') // throw new Error('not allow store line.')
} }
updateLine(start: ItemJson, end: ItemJson, type: LinkType, option?: RendererCudOption) { updateLine(start: ItemJson, end: ItemJson, type: LinkType, option?: RendererCudOption) {
throw new Error('not allow store line.') // throw new Error('not allow store line.')
} }
/** /**
* *
* item.dt.storeAt , { item:'货架ID', bay:0, level:1, cell:0 } * item.dt.storeAt , { item:'货架ID', bay:0, level:1, cell:0 }
*/ */
getStorePlacement(viewport: Viewport, item: ItemJson): { position: [number, number, number], rotation: [number, number, number] } { getStorePlacement(rack: ItemJson, bay = 0, level = 0, cell = 0): { position: [number, number, number], rotation: [number, number, number] } {
if (!item.dt?.storeAt?.item) { // if (!item.dt?.storeAt?.item) {
// 没有定义存储位置,返回空对象 // // 没有定义存储位置,返回空对象
//@ts-ignore // //@ts-ignore
return {} // return {}
} // }
//
const bay = item.dt?.storeAt?.bay || 0 // const bay = item.dt?.storeAt?.bay || 0
const level = item.dt?.storeAt?.level || 0 // const level = item.dt?.storeAt?.level || 0
// 暂时不用算格子 const cell = item.dt?.storeAt?.cell || 0 // 暂时不用算格子 const cell = item.dt?.storeAt?.cell || 0
// 目标货架 // 目标货架
const rack = viewport.stateManager.findItemById(item.dt.storeAt.item) // const rack = viewport.stateManager.findItemById(item.dt.storeAt.item)
const rackWidth = decimalSumBy(rack.dt.bays, (b: any) => b.bayWidth) const rackWidth = decimalSumBy(rack.dt.bays, (b: any) => b.bayWidth)
const bays = rack.dt.bays const bays = rack.dt.bays
const levelHeights = rack.dt.bays[bay]?.levelHeight const levelHeights = rack.dt.bays[bay]?.levelHeight
@ -140,7 +143,7 @@ export default class RackRenderer extends BaseRenderer {
for (const subItemId of subItems) { for (const subItemId of subItems) {
const subItem = getEntity(subItemId) const subItem = getEntity(subItemId)
if (subItem) { if (subItem) {
const { position, rotation } = this.getStorePlacement(viewport, subItem) const { position, rotation } = this.getStorePlacement(item, subItem.dt.storeAt.bay, subItem.dt.storeAt.level, subItem.dt.storeAt.cell)
if (position) { if (position) {
subItem.tf[0][0] = position[0] subItem.tf[0][0] = position[0]
subItem.tf[0][1] = position[1] subItem.tf[0][1] = position[1]

105
src/modules/way/WayRenderer.ts

@ -1,12 +1,15 @@
import * as THREE from 'three' import * as THREE from 'three'
import BaseRenderer from '@/core/base/BaseRenderer.ts' import BaseRenderer from '@/core/base/BaseRenderer.ts'
import MoveLinePointPng from '@/assets/images/moveline_point.png' import MoveLinePointPng from '@/assets/images/moveline_point.png'
import { createLinkPlaneMatrix4, getCargoLineId, getLinkDirection, getMatrixFromTf } from '@/core/ModelUtils.ts' import { createLinkPlaneMatrix4, getCargoLineId, getLineId, getLinkDirection, getMatrixFromTf } from '@/core/ModelUtils.ts'
import Constract from '@/core/Constract.ts' import Constract from '@/core/Constract.ts'
import type { Object3DLike } from '@/types/ModelTypes.ts' import type { LineLike, Object3DLike } from '@/types/ModelTypes.ts'
import TriangleUrl from '@/assets/images/conveyor/shapes/triangle.png?inline' import TriangleUrl from '@/assets/images/conveyor/shapes/triangle.png?inline'
import Triangle2Url from '@/assets/images/conveyor/shapes/triangle-double.png?inline' import Triangle2Url from '@/assets/images/conveyor/shapes/triangle-double.png?inline'
import InstanceMeshManager from '@/core/manager/InstanceMeshManager.ts' import InstanceMeshManager from '@/core/manager/InstanceMeshManager.ts'
import LineSegmentManager from '@/core/manager/LineSegmentManager.ts'
import { LineMaterial } from 'three/examples/jsm/lines/LineMaterial'
import { getRenderer } from '@/core/manager/ModuleManager.ts'
/** /**
* AGV行走路线渲染器 point * AGV行走路线渲染器 point
@ -16,6 +19,7 @@ export default class WayRenderer extends BaseRenderer {
static POINT_NAME = 'way_point' static POINT_NAME = 'way_point'
static LINE_NAME = 'way_line' static LINE_NAME = 'way_line'
static GUIDEWAY_LINE_NAME = 'guideway' static GUIDEWAY_LINE_NAME = 'guideway'
static RED_LINE_NAME = 'red_line'
pointGeometry: THREE.BufferGeometry pointGeometry: THREE.BufferGeometry
pointMaterial: THREE.Material pointMaterial: THREE.Material
@ -27,6 +31,7 @@ export default class WayRenderer extends BaseRenderer {
// gapSize: 0, // gapSize: 0,
// worldUnits: true // worldUnits: true
// }) // })
redLineMaterial: LineMaterial = new LineMaterial({ color: 0xff0000, linewidth: 1 })
lineGeometry: THREE.BufferGeometry = new THREE.PlaneGeometry(1, 1).rotateX(-Math.PI / 2) lineGeometry: THREE.BufferGeometry = new THREE.PlaneGeometry(1, 1).rotateX(-Math.PI / 2)
lineMaterial = new THREE.MeshBasicMaterial({ lineMaterial = new THREE.MeshBasicMaterial({
color: 0xa0cfff, color: 0xa0cfff,
@ -103,19 +108,48 @@ export default class WayRenderer extends BaseRenderer {
createLine(start: ItemJson, end: ItemJson, type: LinkType): Object3DLike { createLine(start: ItemJson, end: ItemJson, type: LinkType): Object3DLike {
if (start.t === this.itemTypeName && end.t === this.itemTypeName) { if (start.t === this.itemTypeName && end.t === this.itemTypeName) {
return this._createOrUpdateGuideway(start, end, type) // return this._createOrUpdateGuideway(start, end, type)
} else { } else {
// throw new Error('目前只支持二维码站点之间的连接') // throw new Error('目前只支持二维码站点之间的连接')
const lineId = getLineId(start.id, end.id, type)
this.getRedLineManager().createOrUpdateLine(lineId, start.tf[0], end.tf[0], '#ff0000')
} }
} }
updateLine(start: ItemJson, end: ItemJson, type: LinkType, option?: RendererCudOption) { updateLine(start: ItemJson, end: ItemJson, type: LinkType, option?: RendererCudOption) {
if (start.t === this.itemTypeName && end.t === this.itemTypeName) { if (start.t === this.itemTypeName && end.t === this.itemTypeName) {
this.deleteLine(start, end, type) // this.deleteLine(start, end, type)
this._createOrUpdateGuideway(start, end, type) // this._createOrUpdateGuideway(start, end, type)
} else { } else {
// throw new Error('目前只支持二维码站点之间的连接') // throw new Error('目前只支持二维码站点之间的连接')
const lineId = getLineId(start.id, end.id, type)
this.getRedLineManager().createOrUpdateLine(lineId, start.tf[0], end.tf[0], '#ff0000')
}
}
deleteLine(start: ItemJson, end: ItemJson, type: LinkType, option?: RendererCudOption) {
if ((start.t === this.itemTypeName || start.t === 'unknown') && (end.t === this.itemTypeName || end.t === 'unknown')) {
// 二维码站点之间的连接
const lineId = getCargoLineId(WayRenderer.GUIDEWAY_LINE_NAME, start.id, end.id)
const object = this.tempViewport.entityManager.findLineObjectById(lineId)
// 删除箭头
if (object?.userData.dirWraps) {
object.userData.dirWraps.forEach((uuid: string) => {
this.dirPointManager.delete(uuid)
this.dir2PointManager.delete(uuid)
})
}
// 删除这条线
this.guidewayManager.delete(lineId)
this.tempViewport.entityManager.deleteLineObjectOnly(lineId)
} else {
// throw new Error('目前只支持二维码站点之间的连接')
const lineId = getLineId(start.id, end.id, type)
this.getRedLineManager().deleteLine(lineId)
} }
} }
@ -221,30 +255,42 @@ export default class WayRenderer extends BaseRenderer {
} }
deleteLine(start: ItemJson, end: ItemJson, type: LinkType, option?: RendererCudOption) { /**
if ((start.t === this.itemTypeName || start.t === 'unknown') && (end.t === this.itemTypeName || end.t === 'unknown')) { *
// 二维码站点之间的连接 */
const lineId = getCargoLineId(WayRenderer.GUIDEWAY_LINE_NAME, start.id, end.id) afterCreateOrUpdatePoint(item: ItemJson, option: RendererCudOption, object: Object3DLike) {
const object = this.tempViewport.entityManager.findLineObjectById(lineId) super.afterCreateOrUpdatePoint(item, option, object)
// 创建一个 id 标签
this.tempViewport.labelManager.createOrUpdateMeshLabel(object, '' + item.id, {
name: Constract.WAY_ID_LABEL,
useHtmlLabel: false,
fontSize: 0.3,
color: '#000000',
offset: new THREE.Vector3(0, 5, 0)
})
// 删除箭头 // 查看 linkStoreAt 属性
if (object?.userData.dirWraps) { if (item.dt.linkStoreAt?.item) {
object.userData.dirWraps.forEach((uuid: string) => { // 如果有 linkStoreAt 属性,则创建一个标签
this.dirPointManager.delete(uuid) const lineId = getLineId(item.id, item.dt.linkStoreAt.item, 'center')
this.dir2PointManager.delete(uuid) const rack = this.tempViewport.stateManager.findItemById(item.dt.linkStoreAt.item)
}) if (rack) {
const rackRenderer = getRenderer(rack.t)
if (rackRenderer) {
const { position, rotation } = rackRenderer.getStorePlacement(rack, item.dt.linkStoreAt.bay, item.dt.linkStoreAt.level, item.dt.linkStoreAt.cell)
if (!position || !Array.isArray(position) || position.length < 3) {
console.warn('linkStoreAt position is invalid', item.dt.linkStoreAt)
return
} else {
this.redLineManager.createOrUpdateLine(lineId, item.tf[0], [position[0], 0, position[2]], '#ff0000')
}
}
} }
// 删除这条线
this.guidewayManager.delete(lineId)
this.tempViewport.entityManager.deleteLineObjectOnly(lineId)
} else {
// throw new Error('目前只支持二维码站点之间的连接')
} }
} }
afterCreateOrUpdateLine(start: ItemJson, end: ItemJson, type: LinkType, option: RendererCudOption, object: Object3DLike) { afterCreateOrUpdateLine(start: ItemJson, end: ItemJson, type: LinkType, option: RendererCudOption, object: LineLike) {
const startPosition = new THREE.Vector3(start.tf[0][0], this.defulePositionY, start.tf[0][2]) const startPosition = new THREE.Vector3(start.tf[0][0], this.defulePositionY, start.tf[0][2])
const endPosition = new THREE.Vector3(end.tf[0][0], this.defulePositionY, end.tf[0][2]) const endPosition = new THREE.Vector3(end.tf[0][0], this.defulePositionY, end.tf[0][2])
@ -312,6 +358,17 @@ export default class WayRenderer extends BaseRenderer {
this.lineMaterial?.dispose() this.lineMaterial?.dispose()
} }
get redLineManager(): LineSegmentManager {
if (!this.tempViewport) {
throw new Error('tempViewport is not set.')
}
const name = WayRenderer.RED_LINE_NAME
return this.tempViewport.getOrCreateLineManager(name, () => {
// 构建 LineSegment.points 代理对象
return new LineSegmentManager(name, this.tempViewport, this.redLineMaterial)
})
}
get guidewayManager(): InstanceMeshManager { get guidewayManager(): InstanceMeshManager {
if (!this.tempViewport) { if (!this.tempViewport) {
throw new Error('tempViewport is not set.') throw new Error('tempViewport is not set.')

10
src/types/model.d.ts

@ -230,6 +230,16 @@ interface ItemJson extends ItemMetrix {
cell?: number // 货架(地堆货位)的格 cell?: number // 货架(地堆货位)的格
} }
/**
* , 线
*/
linkStoreAt?: {
item: string, // 货架(地堆货位)ID
bay?: number, // 货架(地堆货位)的列
level?: number // 货架(地堆货位)的层
cell?: number // 货架(地堆货位)的格
}
bays?: { bays?: {
bayWidth: number, bayWidth: number,
levelHeight: number[] levelHeight: number[]

Loading…
Cancel
Save