Browse Source

pallet 和 tote

master
修宁 6 months ago
parent
commit
4ba5e1c361
  1. BIN
      src/assets/Models/PallTex.png
  2. BIN
      src/assets/Models/Pallet.3ds
  3. BIN
      src/assets/Models/Queue/QueTex.png
  4. BIN
      src/assets/Models/Queue/Queue.3ds
  5. BIN
      src/assets/Models/Tote.3ds
  6. BIN
      src/assets/Models/ToteTex.png
  7. 1
      src/core/Constract.ts
  8. 36
      src/core/ModelUtils.ts
  9. 2
      src/core/manager/WorldModel.ts
  10. 4
      src/example/ExampleUtil.js
  11. 15
      src/example/example1.js
  12. 8
      src/modules/gstore/GstoreRenderer.ts
  13. 3
      src/modules/measure/MeasureRenderer.ts
  14. 127
      src/modules/pallet/PalletRenderer.ts
  15. 5
      src/modules/tote/ToteEntity.ts
  16. 22
      src/modules/tote/ToteInteraction.ts
  17. 20
      src/modules/tote/TotePropertySetter.ts
  18. 75
      src/modules/tote/ToteRenderer.ts
  19. 15
      src/modules/tote/index.ts

BIN
src/assets/Models/PallTex.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 438 KiB

BIN
src/assets/Models/Pallet.3ds

Binary file not shown.

BIN
src/assets/Models/Queue/QueTex.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 234 KiB

BIN
src/assets/Models/Queue/Queue.3ds

Binary file not shown.

BIN
src/assets/Models/Tote.3ds

Binary file not shown.

BIN
src/assets/Models/ToteTex.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 81 KiB

1
src/core/Constract.ts

@ -35,5 +35,6 @@ const Constract = Object.freeze({
MAX_MEASURE_INSTANCES: 1000,
MAX_GSTORE_INSTANCES: 500,
MAX_PALLET_INSTANCES: 10000,
})
export default Constract

36
src/core/ModelUtils.ts

@ -6,6 +6,10 @@ import { Vector2 } from 'three/src/math/Vector2'
import EventBus from '@/runtime/EventBus.ts'
import Decimal from 'decimal.js'
import type { Object3DLike } from '@/types/ModelTypes.ts'
import axios from 'axios'
import { FBXLoader } from 'three/examples/jsm/loaders/FBXLoader'
import { OBJLoader } from 'three/examples/jsm/loaders/OBJLoader'
import { TDSLoader } from 'three/examples/jsm/loaders/TDSLoader'
export function setUserDataForItem(item: ItemJson, object: Object3DLike) {
if (!object.name && item.name) {
@ -483,3 +487,35 @@ export function decimalSumBy<T>(collection: ArrayLike<T> | null | undefined, ite
})
return sum.toNumber()
}
export async function loadByUrl(url): Promise<any> {
return await axios.get(url, {
responseType: 'arraybuffer'
})
}
export function loadTexture(url: string) {
return new THREE.TextureLoader().loadAsync(url)
}
export function load3DModule(arrayBuffer: ArrayBuffer | string, ext: string) {
if (ext.endsWith('.fbx')) {
system.showLoading()
const loader = new FBXLoader()
return loader.parse(arrayBuffer, '')
} else if (ext.endsWith('.obj')) {
const loader = new OBJLoader()
//@ts-ignore
return loader.parse(arrayBuffer)
} else if (ext.endsWith('.3ds')) {
const loader = new TDSLoader()
//@ts-ignore
return loader.parse(arrayBuffer, '')
} else {
system.showErrorDialog('不支持的文件类型!')
return null
}
}

2
src/core/manager/WorldModel.ts

@ -6,6 +6,7 @@ import Way from '@/modules/way'
import Gstore from '@/modules/gstore'
import Rack from '@/modules/rack'
import Pallet from "@/modules/pallet"
import Tote from "@/modules/tote"
import Ptr from "@/modules/ptr"
import Clx from "@/modules/clx"
import Charger from "@/modules/charger"
@ -72,6 +73,7 @@ export default class WorldModel {
Gstore,
Rack,
Pallet,
Tote,
Ptr,
Clx,
Charger

4
src/example/ExampleUtil.js

@ -5,8 +5,8 @@
* @param cols
*/
export function buildPointPerformanceData(t, rows, cols) {
const spacingX = 1.25 // X轴间距
const spacingZ = 1.25 // Y轴间距
const spacingX = 1.5 // X轴间距
const spacingZ = 1.5 // Y轴间距
// 创建一个二维数组来存储点阵数据
const data = new Map()

15
src/example/example1.js

@ -326,17 +326,10 @@ export default {
catalogCode: 'f3', t: 'floor',
items: [
{
id: 'gstore3',
t: 'gstore',
v: true,
tf: [[0, 0.1, 0], [0, 0, 0], [2.0, 0.1, 1.0]],
dt: { in: [], out: [], center: [], storeWidth: 1.4, storeDepth: 1.4 }
},
{
id: 'gstore4',
t: 'gstore',
id: 'tote1',
t: 'pallet',
v: true,
tf: [[5, 0.1, 0], [0, 0, 0], [2.0, 0.1, 1.0]],
tf: [[0, 0.1, 0], [0, 0, 0], [1.0, 0.1, 1.0]],
dt: { in: [], out: [], center: [], storeWidth: 1.4, storeDepth: 1.4 }
}
]
@ -347,7 +340,7 @@ export default {
},
{
catalogCode: '__f2', t: 'floor',
items: buildPointPerformanceData('gstore', 10, 10)
items: buildPointPerformanceData('pallet', 10, 10)
}
],
elevator: [], // 电梯

8
src/modules/gstore/GstoreRenderer.ts

@ -1,15 +1,11 @@
import * as THREE from 'three'
import * as IfxUtils from '@/core/IfxUtils.ts'
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 Constract from '@/core/Constract.ts'
import InstancePointManager from '@/core/manager/InstancePointManager.ts'
import { BasePlane, type Object3DLike } from '@/types/ModelTypes.ts'
import { type Object3DLike } from '@/types/ModelTypes.ts'
/**
*
* 使 InstanceMesh
*/
export default class GstoreRenderer extends BaseRenderer {
static POINT_NAME = 'ground_store'

3
src/modules/measure/MeasureRenderer.ts

@ -9,6 +9,7 @@ import type { Object3DLike } from '@/types/ModelTypes.ts'
/**
*
* InstanceMesh LineSegment
*/
export default class MeasureRenderer extends BaseRenderer {
static LABEL_NAME = 'measure_label'
@ -38,6 +39,7 @@ export default class MeasureRenderer extends BaseRenderer {
throw new Error('tempViewport is not set.')
}
return this.tempViewport.getOrCreatePointManager(this.itemTypeName, () =>
// 构建 InstanceMesh 代理对象
InstancePointManager.create(this.itemTypeName,
this.tempViewport,
this.pointGeometry,
@ -51,6 +53,7 @@ export default class MeasureRenderer extends BaseRenderer {
throw new Error('tempViewport is not set.')
}
return this.tempViewport.getOrCreateLineManager(this.itemTypeName, () =>
// 构建 LineSegment.points 代理对象
LineSegmentManager.create(this.itemTypeName,
this.tempViewport,
this.lineMaterial)

127
src/modules/pallet/PalletRenderer.ts

@ -1,18 +1,17 @@
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 InstancePointManager from '@/core/manager/InstancePointManager.ts'
import type { Object3DLike } from '@/types/ModelTypes.ts'
import MODULE_3DS_File from '@/assets/Models/Pallet.3ds?url'
import MODULE_3DS_TEX from '@/assets/Models/PallTex.png?url'
import { load3DModule, loadByUrl, loadTexture } from '@/core/ModelUtils.ts'
/**
*
*/
export default class PalletRenderer extends BaseRenderer {
static POINT_NAME = 'pallet'
pointMaterial: THREE.Material
static POINT_NAME = 'pallet_point'
/**
* ,
@ -20,91 +19,55 @@ export default class PalletRenderer extends BaseRenderer {
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, object: THREE.Object3D) {
super.afterCreateOrUpdatePoint(item, option, object)
const point = object
// 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])
)
readonly defaultUserData = {
color: 0xcfc195
}
createLineBasic(start: ItemJson, end: ItemJson, type: LinkType): THREE.Object3D {
throw new Error('not allow store line.')
palletGeometry: THREE.BufferGeometry
palletMaterial: THREE.Material
init() {
return Promise.all([
super.init(),
loadByUrl(MODULE_3DS_File),
loadTexture(MODULE_3DS_TEX)
]).then(([_, { data: queue3dsFile }, queueTexture]) => {
const mesh = load3DModule(queue3dsFile, '.3ds').children[0] as THREE.Mesh
this.palletGeometry = mesh.geometry.rotateX(-Math.PI / 2)
this.palletMaterial = mesh.material as THREE.Material
this.palletMaterial.color.set(this.defaultUserData.color)
this.palletMaterial.map = queueTexture
})
}
updateLine(start: ItemJson, end: ItemJson, type: LinkType, option?: RendererCudOption) {
throw new Error('not allow store line.')
createPointBasic(item: ItemJson, option?: RendererCudOption): Object3DLike {
return this.pointManager.createPoint(item)
}
createPoint(item: ItemJson, option?: RendererCudOption): THREE.Object3D {
// 创建平面几何体
if (!item.dt.palletWidth || !item.dt.palletDepth) {
system.showErrorDialog('field palletWidth / palletDepth is null!')
return null
get pointManager(): InstancePointManager {
if (!this.tempViewport) {
throw new Error('tempViewport is not set.')
}
const group = new THREE.Group()
group.name = PalletRenderer.POINT_NAME
// 绘制背景矩形框
const planeGeometry = new THREE.PlaneGeometry(item.dt.palletWidth - this.defaultLineWidth, item.dt.palletDepth - this.defaultLineWidth)
planeGeometry.rotateX(Math.PI / 2)
const planeMaterial = new THREE.MeshBasicMaterial({
color: '#029de5',
side: THREE.DoubleSide // 双面渲染:ml-citation{ref="5,8" data="citationList"}
})
const planeMesh = new THREE.Mesh(planeGeometry, planeMaterial)
group.add(planeMesh)
// 绘制边框
const lineXLen = item.dt.palletWidth - this.defaultLineWidth
const lineYLen = item.dt.palletDepth - 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)
])
const lineMaterial = new LineMaterial({
color: '#029de5',
linewidth: this.defaultLineWidth,
worldUnits: true,
resolution: new THREE.Vector2(window.innerWidth, window.innerHeight),
side: THREE.DoubleSide
})
//
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])
return group
return this.tempViewport.getOrCreatePointManager(this.itemTypeName, () =>
// 构建 InstanceMesh 代理对象
InstancePointManager.create(this.itemTypeName,
this.tempViewport,
this.palletGeometry,
this.palletMaterial,
Constract.MAX_PALLET_INSTANCES)
)
}
dispose() {
super.dispose()
this.pointMaterial?.dispose()
}
createPointBasic(item: ItemJson, option?: RendererCudOption): THREE.Object3D {
throw new Error('Pallet createPointBasic not allow!')
if (this.palletGeometry) {
this.palletGeometry.dispose()
this.palletGeometry = undefined
}
if (this.palletMaterial) {
this.palletMaterial.dispose()
this.palletMaterial = undefined
}
}
}

5
src/modules/tote/ToteEntity.ts

@ -0,0 +1,5 @@
import BaseEntity from '@/core/base/BaseItemEntity.ts'
export default class PalletEntity extends BaseEntity {
}

22
src/modules/tote/ToteInteraction.ts

@ -0,0 +1,22 @@
import BaseInteraction from '@/core/base/BaseInteraction.ts'
import * as THREE from 'three'
export default class PalletInteraction 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
}
}

20
src/modules/tote/TotePropertySetter.ts

@ -0,0 +1,20 @@
import type { PropertySetter } from "@/core/base/PropertyTypes.ts";
import { basicFieldsSetter } from "@/editor/widgets/property/PropertyPanelConstant.ts";
const propertySetter: PropertySetter = {
flatten: {
fields: [
...basicFieldsSetter,
{
dataPath: 'dt.palletWidth', label: '托盘宽度', input: 'InputNumber',
inputProps: {},
},
{
dataPath: 'dt.palletDepth', label: '托盘深度', input: 'InputNumber',
inputProps: {},
},
],
},
};
export default propertySetter;

75
src/modules/tote/ToteRenderer.ts

@ -0,0 +1,75 @@
import * as THREE from 'three'
import BaseRenderer from '@/core/base/BaseRenderer.ts'
import Constract from '@/core/Constract.ts'
import InstancePointManager from '@/core/manager/InstancePointManager.ts'
import type { Object3DLike } from '@/types/ModelTypes.ts'
import MODULE_3DS_File from '@/assets/Models/Tote.3ds?url'
import MODULE_3DS_TEX from '@/assets/Models/ToteTex.png?url'
import { load3DModule, loadByUrl, loadTexture } from '@/core/ModelUtils.ts'
/**
*
*/
export default class PalletRenderer extends BaseRenderer {
static POINT_NAME = 'pallet_point'
/**
* ,
*/
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 defaultUserData = {
color: 0x4559A0
}
toteGeometry: THREE.BufferGeometry
toteMaterial: THREE.Material
init() {
return Promise.all([
super.init(),
loadByUrl(MODULE_3DS_File),
loadTexture(MODULE_3DS_TEX)
]).then(([_, { data: queue3dsFile }, queueTexture]) => {
const mesh = load3DModule(queue3dsFile, '.3ds').children[0] as THREE.Mesh
this.toteGeometry = mesh.geometry.rotateX(-Math.PI / 2)
this.toteGeometry.scale(1, 1, 1)
this.toteGeometry.center()
this.toteMaterial = mesh.material as THREE.Material
this.toteMaterial.map = queueTexture
this.toteMaterial.color.set(this.defaultUserData.color)
})
}
createPointBasic(item: ItemJson, option?: RendererCudOption): Object3DLike {
return this.pointManager.createPoint(item)
}
get pointManager(): InstancePointManager {
if (!this.tempViewport) {
throw new Error('tempViewport is not set.')
}
return this.tempViewport.getOrCreatePointManager(this.itemTypeName, () =>
// 构建 InstanceMesh 代理对象
InstancePointManager.create(this.itemTypeName,
this.tempViewport,
this.toteGeometry,
this.toteMaterial,
Constract.MAX_PALLET_INSTANCES)
)
}
dispose() {
super.dispose()
if (this.toteGeometry) {
this.toteGeometry.dispose()
this.toteGeometry = undefined
}
if (this.toteMaterial) {
this.toteMaterial.dispose()
this.toteMaterial = undefined
}
}
}

15
src/modules/tote/index.ts

@ -0,0 +1,15 @@
import { defineModule } from '@/core/manager/ModuleManager.ts'
import ToteRenderer from './ToteRenderer.ts'
import ToteEntity from './ToteEntity.ts'
import ToteInteraction from './ToteInteraction.ts'
import propertySetter from './TotePropertySetter.ts'
export const ITEM_TYPE_NAME = 'tote'
export default defineModule({
name: ITEM_TYPE_NAME,
renderer: new ToteRenderer(ITEM_TYPE_NAME),
interaction: new ToteInteraction(ITEM_TYPE_NAME),
setter: propertySetter,
entity: ToteEntity
})
Loading…
Cancel
Save