Browse Source

解决循环依赖问题、世界模型初始化时机问题

master
修宁 6 months ago
parent
commit
c19f6d6fbc
  1. 3
      src/core/ModelUtils.ts
  2. 2
      src/core/base/BaseRenderer.ts
  3. 6
      src/core/manager/CodeDropper.ts
  4. 44
      src/core/manager/ModuleManager.ts
  5. 41
      src/core/manager/WorldModel.ts
  6. 2
      src/editor/CatalogDefine.vue
  7. 1
      src/editor/Model2DEditor.vue
  8. 33
      src/editor/ModelMain.vue
  9. 5
      src/editor/ModelMainInit.ts
  10. 181
      src/editor/menus/FileMenu.ts
  11. 1
      src/editor/widgets/modeltree/ModeltreeViewJs.js
  12. 2
      src/main.ts
  13. 7
      src/modules/agv1/index.ts
  14. 13
      src/modules/carton/index.ts
  15. 13
      src/modules/charger/index.ts
  16. 13
      src/modules/cl2/index.ts
  17. 14
      src/modules/clx/index.ts
  18. 13
      src/modules/gstore/index.ts
  19. 3
      src/modules/measure/MeasureRenderer.ts
  20. 15
      src/modules/measure/index.ts
  21. 13
      src/modules/pallet/index.ts
  22. 760
      src/modules/rack/RackRenderer.ts_back
  23. 13
      src/modules/rack/index.ts
  24. 13
      src/modules/shuttle_rack/index.ts
  25. 7
      src/modules/tote/index.ts
  26. 13
      src/modules/way/index.ts
  27. 3
      src/types/global.d.ts

3
src/core/ModelUtils.ts

@ -1,7 +1,6 @@
import * as THREE from 'three' import * as THREE from 'three'
import type Viewport from '@/core/engine/Viewport' import type Viewport from '@/core/engine/Viewport'
import { Vector2 } from 'three/src/math/Vector2' import { Vector2 } from 'three/src/math/Vector2'
import EventBus from '@/runtime/EventBus.ts'
import Decimal from 'decimal.js' import Decimal from 'decimal.js'
import type { LineLike, Object3DLike } from '@/types/ModelTypes.ts' import type { LineLike, Object3DLike } from '@/types/ModelTypes.ts'
import axios from 'axios' import axios from 'axios'
@ -9,7 +8,7 @@ import { FBXLoader } from 'three/examples/jsm/loaders/FBXLoader'
import { OBJLoader } from 'three/examples/jsm/loaders/OBJLoader' import { OBJLoader } from 'three/examples/jsm/loaders/OBJLoader'
import { TDSLoader } from 'three/examples/jsm/loaders/TDSLoader' import { TDSLoader } from 'three/examples/jsm/loaders/TDSLoader'
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader' import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader'
import { LineSegments2 } from 'three/examples/jsm/lines/LineSegments2' import { worldModel } from '@/core/manager/WorldModel.ts'
import { LineMaterial } from 'three/examples/jsm/lines/LineMaterial' import { LineMaterial } from 'three/examples/jsm/lines/LineMaterial'
import { Line2 } from 'three/examples/jsm/lines/Line2' import { Line2 } from 'three/examples/jsm/lines/Line2'
import { LineGeometry } from 'three/examples/jsm/lines/LineGeometry' import { LineGeometry } from 'three/examples/jsm/lines/LineGeometry'

2
src/core/base/BaseRenderer.ts

@ -7,6 +7,8 @@ import type { LineLike, Object3DLike } from '@/types/ModelTypes.ts'
import { MeshWrap } from '@/core/manager/InstanceMeshManager.ts' import { MeshWrap } from '@/core/manager/InstanceMeshManager.ts'
import { getRenderer } from '@/core/manager/ModuleManager.ts' import { getRenderer } from '@/core/manager/ModuleManager.ts'
debugger
/** /**
* *
* / 线 Three.js . * / 线 Three.js .

6
src/core/manager/CodeDropper.ts

@ -42,7 +42,7 @@ export default class CodeDropper extends BaseInteraction {
droppedItemCallback: (item: ItemJson, pos: THREE.Vector3, evt: MouseEvent) => boolean droppedItemCallback: (item: ItemJson, pos: THREE.Vector3, evt: MouseEvent) => boolean
} }
defineModule({ const ITEM_NAME = 'CodeDropper'
name: 'CodeDropper', defineModule(ITEM_NAME, () => ({
interaction: CodeDropper.INSTANCE interaction: CodeDropper.INSTANCE
}) }))

44
src/core/manager/ModuleManager.ts

@ -1,17 +1,20 @@
import * as THREE from 'three'
import BaseRenderer from '@/core/base/BaseRenderer' import BaseRenderer from '@/core/base/BaseRenderer'
import BaseInteraction from '@/core/base/BaseInteraction' import BaseInteraction from '@/core/base/BaseInteraction'
import BaseEntity from '@/core/base/BaseItemEntity' import type { PropertySetter } from '@/core/base/PropertyTypes.ts'
import type { PropertySetter } from "@/core/base/PropertyTypes.ts";
// Define the ModuleDefineOption interface // Define the ModuleDefineOption interface
export interface ModuleDefineOption { export interface ModuleDefineOption {
/** /**
* *
*/ */
name: string;
renderer?: BaseRenderer; renderer?: BaseRenderer;
/**
*
*/
interaction?: BaseInteraction; interaction?: BaseInteraction;
/**
*
*/
setter?: PropertySetter; setter?: PropertySetter;
} }
@ -22,12 +25,19 @@ window['modules'] = modules
/** /**
* *
*/ */
export function defineModule(option: ModuleDefineOption): Promise<any> { export function defineModule(name: string, optionFn: () => ModuleDefineOption): Promise<any> {
if (modules.has(option.name)) { if (modules.has(name)) {
throw new Error(`Module with name "${option.name}" is already defined.`) throw new Error(`Module with name "${name}" is already defined.`)
} }
modules.set(option.name, option) return new Promise((resolve) => {
return option.renderer?.init() if (typeof optionFn !== 'function') {
console.log(`Module "${name}" is not a function, using it directly.`)
debugger
}
const option = optionFn()
modules.set(name, option)
option.renderer?.init().then(resolve)
})
} }
/** /**
@ -62,17 +72,5 @@ export function getInteraction<T extends BaseInteraction>(name: string): T {
export function getSetter(name: string) { export function getSetter(name: string) {
const module = getModuleOption(name) const module = getModuleOption(name)
return module.setter; return module.setter
}
/**
* ,
*
*/
export function createEntity<T extends BaseEntity>(name: string, itemjson: ItemJson, objects: THREE.Object3D[]): T {
const module = getModuleOption(name)
const v = new module.entity() as T
v.setItem(itemjson)
v.setObjects(objects)
return v
} }

41
src/core/manager/WorldModel.ts

@ -1,18 +1,6 @@
import _, { cloneDeep } from 'lodash' import _, { cloneDeep } from 'lodash'
import { reactive, watch } from 'vue' import { reactive, watch } from 'vue'
import EventBus from '@/runtime/EventBus' import EventBus from '@/runtime/EventBus'
import Measure from '@/modules/measure'
import Way from '@/modules/way'
import Gstore from '@/modules/gstore'
import Rack from '@/modules/rack'
import ShuttleRack from '@/modules/shuttle_rack'
import Pallet from '@/modules/pallet'
import Tote from '@/modules/tote'
// import Agv1 from '@/modules/agv1'
import Carton from '@/modules/carton'
import Cl2 from '@/modules/cl2'
import Clx from '@/modules/clx'
import Charger from '@/modules/charger'
import StateManager from '@/core/manager/StateManager.ts' import StateManager from '@/core/manager/StateManager.ts'
import { getQueryParams, setQueryParam } from '@/utils/webutils.ts' import { getQueryParams, setQueryParam } from '@/utils/webutils.ts'
import localforage from 'localforage' import localforage from 'localforage'
@ -68,7 +56,7 @@ export default class WorldModel {
isLoading: false, isLoading: false,
isRunning: false, isRunning: false,
isVirtual: false, isVirtual: false,
timeRate: 1, timeRate: 1
} }
}) })
@ -101,18 +89,17 @@ export default class WorldModel {
init() { init() {
// 观察 this.state.catalogCode 的变化, 如果变化就调用 catalogCodeChange 方法 // 观察 this.state.catalogCode 的变化, 如果变化就调用 catalogCodeChange 方法
return Promise.all([ return Promise.all([
Measure, import('../../modules/measure'),
Way, import('../../modules/way'),
Gstore, import('../../modules/gstore'),
Rack, import('../../modules/rack'),
ShuttleRack, import('../../modules/shuttle_rack'),
Pallet, import('../../modules/pallet'),
Tote, import('../../modules/tote'),
Carton, import('../../modules/carton'),
Cl2, import('../../modules/cl2'),
Clx, import('../../modules/clx'),
// Agv1, import('../../modules/charger')
Charger
]).then(() => { ]).then(() => {
console.log('世界模型初始化完成') console.log('世界模型初始化完成')
@ -241,3 +228,7 @@ export default class WorldModel {
}) })
} }
} }
const worldModel = new WorldModel()
debugger
export { worldModel }

2
src/editor/CatalogDefine.vue

@ -3,6 +3,7 @@ import { computed, createVNode, reactive, useTemplateRef } from "vue";
import { ElButton, ElSpace, ElTree } from "element-plus"; import { ElButton, ElSpace, ElTree } from "element-plus";
import YvSrcEditor from "@/components/YvSrcEditor.vue"; import YvSrcEditor from "@/components/YvSrcEditor.vue";
import DataForm from "@/components/data-form/DataForm.vue"; import DataForm from "@/components/data-form/DataForm.vue";
import {worldModel} from '@/core/manager/WorldModel.ts'
import lodash from "lodash"; import lodash from "lodash";
defineOptions({ defineOptions({
@ -39,7 +40,6 @@ interface CatalogDefineData {
// //
const data: CatalogDefineData = {}; const data: CatalogDefineData = {};
const tree = useTemplateRef<InstanceType<typeof ElTree>>("treeRef"); const tree = useTemplateRef<InstanceType<typeof ElTree>>("treeRef");
const worldModel = computed(() => window['worldModel']);
const catalog = computed<Array<any>>(() => { const catalog = computed<Array<any>>(() => {
// state.forceUpdateForCatalog; // state.forceUpdateForCatalog;
return worldModel.value?.state?.catalog; return worldModel.value?.state?.catalog;

1
src/editor/Model2DEditor.vue

@ -104,6 +104,7 @@ import { renderIcon, setQueryParam } from '@/utils/webutils'
import { createVNode, defineComponent, markRaw } from 'vue' import { createVNode, defineComponent, markRaw } from 'vue'
import Viewport from '@/core/engine/Viewport' import Viewport from '@/core/engine/Viewport'
import Constract from '@/core/Constract' import Constract from '@/core/Constract'
import { worldModel } from '@/core/manager/WorldModel.ts'
import EventBus from '@/runtime/EventBus' import EventBus from '@/runtime/EventBus'
import SceneHelp from '@/core/engine/SceneHelp' import SceneHelp from '@/core/engine/SceneHelp'
import BulkCopy from './BulkCopy.vue' import BulkCopy from './BulkCopy.vue'

33
src/editor/ModelMain.vue

@ -9,10 +9,10 @@
<component :is="renderIcon('element ArrowDown')"></component> <component :is="renderIcon('element ArrowDown')"></component>
</div> </div>
<div style="flex-grow: 1;"></div> <div style="flex-grow: 1;"></div>
<div style="display: flex; flex-direction: row; align-items: center; margin-right: 10px;"> <div v-if="isModelOpen" style="display: flex; flex-direction: row; align-items: center; margin-right: 10px;">
<div class="field-block" style="margin-right: 5px;"> <div class="field-block" style="margin-right: 5px;">
<el-select style="width:130px;" placeholder="运行环境" <el-select style="width:130px;" placeholder="运行环境"
v-model="worldModel.state.currentEnvId"> v-model="worldModelState.currentEnvId">
<template #footer> <template #footer>
<el-button size="small" type="primary" plain>创建运行环境</el-button> <el-button size="small" type="primary" plain>创建运行环境</el-button>
<el-button size="small" :icon="renderIcon('Refresh')" @click="reloadEnvList" /> <el-button size="small" :icon="renderIcon('Refresh')" @click="reloadEnvList" />
@ -21,20 +21,20 @@
</div> </div>
<div class="field-block" style="margin-right: 5px;"> <div class="field-block" style="margin-right: 5px;">
<el-select style="width:130px;" placeholder="时间速率" <el-select style="width:130px;" placeholder="时间速率"
v-model="worldModel.state.timeRate"> v-model="worldModelState.timeRate">
<el-option label="1x" :value="1"></el-option> <el-option label="1x" :value="1"></el-option>
<el-option label="2x" :value="2"></el-option> <el-option label="2x" :value="2"></el-option>
<el-option label="10x" :value="10"></el-option> <el-option label="10x" :value="10"></el-option>
</el-select> </el-select>
</div> </div>
<el-button :icon="renderIcon('Play')" type="primary" <el-button :icon="renderIcon('Play')" type="primary"
v-if="!worldModel.state.runState.isRunning" v-if="!worldModelState.runState.isRunning"
:disabled="!worldModel.state.runState.currentEnvId" :disabled="!worldModelState.runState.currentEnvId"
:loading="worldModel.state.runState.isLoading">启动 :loading="worldModelState.runState.isLoading">启动
</el-button> </el-button>
<el-button :icon="renderIcon('Stop')" type="danger" plain <el-button :icon="renderIcon('Stop')" type="danger" plain
v-if="worldModel.state.runState.isRunning" v-if="worldModelState.runState.isRunning"
:loading="worldModel.state.runState.isLoading">停止 :loading="worldModelState.runState.isLoading">停止
</el-button> </el-button>
</div> </div>
</div> </div>
@ -47,7 +47,7 @@
</span> </span>
</div> </div>
</div> </div>
<div class="app-section" v-if="worldModel.state.isOpened"> <div class="app-section" v-if="worldModelState.isOpened">
<div class="btns-toolbar btns-toolbar-left"> <div class="btns-toolbar btns-toolbar-left">
<div class="btns btns-top"> <div class="btns btns-top">
<template v-for="panel in getWidgetBySide('left')"> <template v-for="panel in getWidgetBySide('left')">
@ -150,6 +150,7 @@ import Logo from '@/assets/images/logo.png'
import './ModelMain.less' import './ModelMain.less'
import EventBus from '@/runtime/EventBus.js' import EventBus from '@/runtime/EventBus.js'
import { useRouter } from 'vue-router' import { useRouter } from 'vue-router'
import { worldModel } from '@/core/manager/WorldModel.ts'
import runManager from '@/core/manager/RunManager.js' import runManager from '@/core/manager/RunManager.js'
export default { export default {
@ -225,10 +226,10 @@ export default {
}, },
computed: { computed: {
isModelOpen() { isModelOpen() {
return this.worldModel.state.isOpened return this.worldModelState.isOpened
}, },
worldModel() { worldModelState() {
return window['worldModel'] return worldModel.state
}, },
calcLeftPanel() { calcLeftPanel() {
if (!this.sectionLeftName || this.hideLeft) { if (!this.sectionLeftName || this.hideLeft) {
@ -260,6 +261,12 @@ export default {
} }
}, },
watch: { watch: {
'worldModel.state.project_uuid': {
handler() {
this.reloadEnvList()
},
immediate: true
},
hideBottom(value) { hideBottom(value) {
if (value) { if (value) {
this.$refs.mainSplit.refreshSize([100, 0]) this.$refs.mainSplit.refreshSize([100, 0])
@ -278,7 +285,7 @@ export default {
renderIcon, renderIcon,
getWidgetBySide, getWidgetBySide,
reloadEnvList() { reloadEnvList() {
runManager.getAllEnv(this.worldModel.state.project_uuid).then(res => { runManager.getAllEnv(this.worldModelState.project_uuid).then(res => {
this.envList = res.data this.envList = res.data
}) })
}, },

5
src/editor/ModelMainInit.ts

@ -13,10 +13,10 @@ import FileMenu from './menus/FileMenu'
import EditMenu from './menus/EditMenu' import EditMenu from './menus/EditMenu'
import ToolsMenu from './menus/Tools' import ToolsMenu from './menus/Tools'
import Model3DView from './menus/Model3DView' import Model3DView from './menus/Model3DView'
import { worldModel } from '@/core/manager/WorldModel.ts'
import { install as ThreeExtendInstall } from '@/core/ThreeExtend.ts' import { install as ThreeExtendInstall } from '@/core/ThreeExtend.ts'
import { forEachMenu } from '@/runtime/DefineMenu' import { forEachMenu } from '@/runtime/DefineMenu'
import { normalizeShortKey } from '@/utils/webutils' import { normalizeShortKey } from '@/utils/webutils'
import WorldModel from '@/core/manager/WorldModel'
/** /**
* *
@ -36,9 +36,6 @@ export function ModelMainInit() {
ToolsMenu.install() ToolsMenu.install()
Model3DView.install() Model3DView.install()
const worldModel = new WorldModel()
window['worldModel'] = worldModel
ThreeExtendInstall() ThreeExtendInstall()
} }

181
src/editor/menus/FileMenu.ts

@ -6,49 +6,50 @@ import type Viewport from '@/core/engine/Viewport.ts'
import DataForm from '@/components/data-form/DataForm.vue' import DataForm from '@/components/data-form/DataForm.vue'
import OpenProject from '../OpenProject.vue' import OpenProject from '../OpenProject.vue'
import { Request } from '@ease-forge/shared' import { Request } from '@ease-forge/shared'
import { worldModel } from '@/core/manager/WorldModel.ts'
function addProject(successful?: Function) { function addProject(successful?: Function) {
const data = { const data = {
server: window.location.origin, server: window.location.origin
}; }
system.showDialog(createVNode(DataForm, { system.showDialog(createVNode(DataForm, {
style: { style: {
paddingRight: "12px", paddingRight: '12px'
}, },
data: data, data: data,
formFields: [ formFields: [
{ {
dataPath: 'projectUuid', label: '项目编号', input: 'Input', dataPath: 'projectUuid', label: '项目编号', input: 'Input',
inputProps: { inputProps: {
placeholder: '请输入项目唯一编号', placeholder: '请输入项目唯一编号'
}, }
}, },
{ {
dataPath: 'projectLabel', label: '项目标题', input: 'Input', dataPath: 'projectLabel', label: '项目标题', input: 'Input',
inputProps: { inputProps: {
placeholder: '请输入项目标题', placeholder: '请输入项目标题'
}, }
}, }
], ],
columnCount: 1, columnCount: 1,
labelWidth: "80px", labelWidth: '80px'
}), { }), {
title: '创建项目', title: '创建项目',
width: 480, width: 480,
height: 200, height: 200,
showClose: true, showClose: true,
showMax: false, showMax: false,
showCancelButton: true, showCancelButton: true,
showOkButton: true, showOkButton: true,
okButtonText: "创建", okButtonText: '创建',
cancelButtonText: "取消", cancelButtonText: '取消'
}).then(() => { }).then(() => {
Request.request.post("/api/workbench/LccModelManager@addProject", data).then(()=> { Request.request.post('/api/workbench/LccModelManager@addProject', data).then(() => {
system.msg("创建成功"); system.msg('创建成功')
successful?.(); successful?.()
}) })
}).finally(); }).finally()
} }
export default defineMenu((menus) => { export default defineMenu((menus) => {
@ -59,65 +60,65 @@ export default defineMenu((menus) => {
[ [
{ {
name: 'open', label: '打开', icon: SvgCode.open, order: 1, tip: 'Ctrl+O', name: 'open', label: '打开', icon: SvgCode.open, order: 1, tip: 'Ctrl+O',
click: async () => { click: async () => {
worldModel.state.isOpened = false
worldModel.state.isDraft = false
worldModel.state.catalog = []
worldModel.state.catalogCode = ''
worldModel.state.stateManagerId = ''
setQueryParam('store', '')
system.showLoading()
try {
await nextTick()
const res = await import('@/example/example1')
worldModel.state.isDraft = false
await worldModel.loadWorldFromRemoting(res.default)
} finally {
system.clearLoading()
}
},
click2: async () => {
let dialog: any = null
system.showDialog(createVNode(OpenProject, {
onCancel: () => dialog?.onClose(),
onOpen: async row => {
dialog?.onClose()
const veryBigData = JSON.parse(row.otherData)
veryBigData.catalog = JSON.parse(row.directoryData)
veryBigData.items = []
worldModel.state.isOpened = false worldModel.state.isOpened = false
worldModel.state.isDraft = false worldModel.state.isDraft = false
worldModel.state.catalog = [] worldModel.state.catalog = []
worldModel.state.catalogCode = '' worldModel.state.catalogCode = ''
worldModel.state.stateManagerId = '' worldModel.state.stateManagerId = ''
setQueryParam('store', '') setQueryParam('store', '')
system.showLoading() system.showLoading()
try { try {
await nextTick() await nextTick()
worldModel.state.isDraft = false
const res = await import('@/example/example1') await worldModel.loadWorldFromRemoting(veryBigData)
worldModel.state.isDraft = false
await worldModel.loadWorldFromRemoting(res.default)
} finally { } finally {
system.clearLoading() system.clearLoading()
} }
}, },
click2: async () => { onAdd: that => {
let dialog: any = null; addProject(() => that.loadData())
system.showDialog(createVNode(OpenProject, { }
onCancel: () => dialog?.onClose(), }), {
onOpen: async row => { title: '打开项目',
dialog?.onClose(); width: 1500,
const veryBigData = JSON.parse(row.otherData); height: 500,
veryBigData.catalog = JSON.parse(row.directoryData); showClose: true,
veryBigData.items = []; showMax: true,
worldModel.state.isOpened = false showCancelButton: false,
worldModel.state.isDraft = false showOkButton: false,
worldModel.state.catalog = [] okButtonText: '创建',
worldModel.state.catalogCode = '' cancelButtonText: '取消',
worldModel.state.stateManagerId = '' onMounted: d => dialog = d
setQueryParam('store', '') }).finally()
system.showLoading()
try {
await nextTick()
worldModel.state.isDraft = false
await worldModel.loadWorldFromRemoting(veryBigData)
} finally {
system.clearLoading()
}
},
onAdd: that => {
addProject(() => that.loadData());
},
}), {
title: '打开项目',
width: 1500,
height: 500,
showClose: true,
showMax: true,
showCancelButton: false,
showOkButton: false,
okButtonText: "创建",
cancelButtonText: "取消",
onMounted: d => dialog = d,
}).finally();
} }
}, },
{ {
@ -131,7 +132,7 @@ export default defineMenu((menus) => {
{ {
name: 'saveAs', label: '新建项目', icon: renderIcon('ModelFile'), order: 3, name: 'saveAs', label: '新建项目', icon: renderIcon('ModelFile'), order: 3,
click: () => { click: () => {
addProject(); addProject()
} }
} }
] ]

1
src/editor/widgets/modeltree/ModeltreeViewJs.js

@ -1,6 +1,7 @@
import { defineComponent, markRaw } from 'vue' import { defineComponent, markRaw } from 'vue'
import YvTable from '@/components/yvTable/YvTable.vue' import YvTable from '@/components/yvTable/YvTable.vue'
import IWidgets from '../IWidgets.js' import IWidgets from '../IWidgets.js'
import { worldModel } from '@/core/manager/WorldModel.ts'
export default defineComponent({ export default defineComponent({
name: 'ModeltreeView', name: 'ModeltreeView',

2
src/main.ts

@ -25,7 +25,7 @@ async function main() {
app.use(webIndex) app.use(webIndex)
app.mount('#app') app.mount('#app')
globalConfig() globalConfig()
await getCurrentUser() // await getCurrentUser()
} }
main().finally() main().finally()

7
src/modules/agv1/index.ts

@ -5,9 +5,8 @@ import propertySetter from './Agv1PropertySetter.ts'
export const ITEM_TYPE_NAME = 'agv1' export const ITEM_TYPE_NAME = 'agv1'
export default defineModule({ export default defineModule(ITEM_TYPE_NAME, () => ({
name: ITEM_TYPE_NAME,
renderer: new Agv1Renderer(ITEM_TYPE_NAME), renderer: new Agv1Renderer(ITEM_TYPE_NAME),
interaction: new Agv1Interaction(ITEM_TYPE_NAME), interaction: new Agv1Interaction(ITEM_TYPE_NAME),
setter: propertySetter, setter: propertySetter
}) }))

13
src/modules/carton/index.ts

@ -1,13 +1,12 @@
import { defineModule } from '@/core/manager/ModuleManager.ts' import { defineModule } from '@/core/manager/ModuleManager.ts'
import CartonRenderer from './CartonRenderer.ts' import CartonRenderer from './CartonRenderer.ts'
import CartonInteraction from './CartonInteraction.ts' import CartonInteraction from './CartonInteraction.ts'
import propertySetter from "./CartonPropertySetter.ts"; import propertySetter from './CartonPropertySetter.ts'
export const ITEM_TYPE_NAME = 'carton' export const ITEM_TYPE_NAME = 'carton'
export default defineModule({ export default defineModule(ITEM_TYPE_NAME, () => ({
name: ITEM_TYPE_NAME, renderer: new CartonRenderer(ITEM_TYPE_NAME),
renderer: new CartonRenderer(ITEM_TYPE_NAME), interaction: new CartonInteraction(ITEM_TYPE_NAME),
interaction: new CartonInteraction(ITEM_TYPE_NAME), setter: propertySetter
setter: propertySetter, }))
})

13
src/modules/charger/index.ts

@ -1,13 +1,12 @@
import { defineModule } from '@/core/manager/ModuleManager.ts' import { defineModule } from '@/core/manager/ModuleManager.ts'
import ChargerRenderer from './ChargerRenderer.ts' import ChargerRenderer from './ChargerRenderer.ts'
import ChargerInteraction from './ChargerInteraction.ts' import ChargerInteraction from './ChargerInteraction.ts'
import propertySetter from "@/modules/charger/ChargerPropertySetter.ts"; import propertySetter from '@/modules/charger/ChargerPropertySetter.ts'
export const ITEM_TYPE_NAME = 'charger' export const ITEM_TYPE_NAME = 'charger'
export default defineModule({ export default defineModule(ITEM_TYPE_NAME, () => ({
name: ITEM_TYPE_NAME, renderer: new ChargerRenderer(ITEM_TYPE_NAME),
renderer: new ChargerRenderer(ITEM_TYPE_NAME), interaction: new ChargerInteraction(ITEM_TYPE_NAME),
interaction: new ChargerInteraction(ITEM_TYPE_NAME), setter: propertySetter
setter: propertySetter, }))
})

13
src/modules/cl2/index.ts

@ -1,13 +1,12 @@
import { defineModule } from '@/core/manager/ModuleManager.ts' import { defineModule } from '@/core/manager/ModuleManager.ts'
import Cl2Renderer from './Cl2Renderer.ts' import Cl2Renderer from './Cl2Renderer.ts'
import Cl2Interaction from './Cl2Interaction.ts' import Cl2Interaction from './Cl2Interaction.ts'
import propertySetter from "./Cl2PropertySetter.ts"; import propertySetter from './Cl2PropertySetter.ts'
export const ITEM_TYPE_NAME = 'cl2' export const ITEM_TYPE_NAME = 'cl2'
export default defineModule({ export default defineModule(ITEM_TYPE_NAME, () => ({
name: ITEM_TYPE_NAME, renderer: new Cl2Renderer(ITEM_TYPE_NAME),
renderer: new Cl2Renderer(ITEM_TYPE_NAME), interaction: new Cl2Interaction(ITEM_TYPE_NAME),
interaction: new Cl2Interaction(ITEM_TYPE_NAME), setter: propertySetter
setter: propertySetter, }))
})

14
src/modules/clx/index.ts

@ -1,13 +1,13 @@
import { defineModule } from '@/core/manager/ModuleManager.ts' import { defineModule } from '@/core/manager/ModuleManager.ts'
import ClxRenderer from './ClxRenderer.ts' import ClxRenderer from './ClxRenderer.ts'
import ClxInteraction from './ClxInteraction.ts' import ClxInteraction from './ClxInteraction.ts'
import propertySetter from "@/modules/clx/ClxPropertySetter.ts"; import propertySetter from '@/modules/clx/ClxPropertySetter.ts'
export const ITEM_TYPE_NAME = 'clx' export const ITEM_TYPE_NAME = 'clx'
export default defineModule({ export default defineModule(ITEM_TYPE_NAME, () => ({
name: ITEM_TYPE_NAME, name: ITEM_TYPE_NAME,
renderer: new ClxRenderer(ITEM_TYPE_NAME), renderer: new ClxRenderer(ITEM_TYPE_NAME),
interaction: new ClxInteraction(ITEM_TYPE_NAME), interaction: new ClxInteraction(ITEM_TYPE_NAME),
setter: propertySetter, setter: propertySetter
}) }))

13
src/modules/gstore/index.ts

@ -1,13 +1,12 @@
import { defineModule } from '@/core/manager/ModuleManager.ts' import { defineModule } from '@/core/manager/ModuleManager.ts'
import GstoreRenderer from './GstoreRenderer.ts' import GstoreRenderer from './GstoreRenderer.ts'
import GstoreInteraction from './GstoreInteraction.ts' import GstoreInteraction from './GstoreInteraction.ts'
import propertySetter from "@/modules/gstore/GstorePropertySetter.ts"; import propertySetter from '@/modules/gstore/GstorePropertySetter.ts'
export const ITEM_TYPE_NAME = 'gstore' export const ITEM_TYPE_NAME = 'gstore'
export default defineModule({ export default defineModule(ITEM_TYPE_NAME, () => ({
name: ITEM_TYPE_NAME, renderer: new GstoreRenderer(ITEM_TYPE_NAME),
renderer: new GstoreRenderer(ITEM_TYPE_NAME), interaction: new GstoreInteraction(ITEM_TYPE_NAME),
interaction: new GstoreInteraction(ITEM_TYPE_NAME), setter: propertySetter
setter: propertySetter, }))
})

3
src/modules/measure/MeasureRenderer.ts

@ -7,6 +7,9 @@ import LineSegmentManager, { LineWrap } from '@/core/manager/LineSegmentManager.
import type { LineLike, Object3DLike } from '@/types/ModelTypes.ts' import type { LineLike, Object3DLike } from '@/types/ModelTypes.ts'
import InstanceMeshManager from '@/core/manager/InstanceMeshManager.ts' import InstanceMeshManager from '@/core/manager/InstanceMeshManager.ts'
debugger
console.log('MeasureRenderer initialized at', performance.now());
/** /**
* *
* InstanceMesh LineSegment * InstanceMesh LineSegment

15
src/modules/measure/index.ts

@ -1,13 +1,14 @@
import { defineModule } from '@/core/manager/ModuleManager.ts' import { defineModule } from '@/core/manager/ModuleManager.ts'
import MeasureRenderer from './MeasureRenderer.ts' import MeasureRenderer from './MeasureRenderer.ts'
import MeasureInteraction from './MeasureInteraction.ts' import MeasureInteraction from './MeasureInteraction.ts'
import propertySetter from "@/modules/measure/MeasurePropertySetter.ts"; import propertySetter from '@/modules/measure/MeasurePropertySetter.ts'
export const ITEM_TYPE_NAME = 'measure' export const ITEM_TYPE_NAME = 'measure'
export default defineModule({ console.log('MeasureRenderer initialized at', performance.now())
name: ITEM_TYPE_NAME,
renderer: new MeasureRenderer(ITEM_TYPE_NAME), export default defineModule(ITEM_TYPE_NAME, () => ({
interaction: new MeasureInteraction(ITEM_TYPE_NAME), renderer: new MeasureRenderer(ITEM_TYPE_NAME),
setter: propertySetter, interaction: new MeasureInteraction(ITEM_TYPE_NAME),
}) setter: propertySetter
}))

13
src/modules/pallet/index.ts

@ -1,13 +1,12 @@
import { defineModule } from '@/core/manager/ModuleManager.ts' import { defineModule } from '@/core/manager/ModuleManager.ts'
import PalletRenderer from './PalletRenderer.ts' import PalletRenderer from './PalletRenderer.ts'
import PalletInteraction from './PalletInteraction.ts' import PalletInteraction from './PalletInteraction.ts'
import propertySetter from "@/modules/pallet/PalletPropertySetter.ts"; import propertySetter from '@/modules/pallet/PalletPropertySetter.ts'
export const ITEM_TYPE_NAME = 'pallet' export const ITEM_TYPE_NAME = 'pallet'
export default defineModule({ export default defineModule(ITEM_TYPE_NAME, () => ({
name: ITEM_TYPE_NAME, renderer: new PalletRenderer(ITEM_TYPE_NAME),
renderer: new PalletRenderer(ITEM_TYPE_NAME), interaction: new PalletInteraction(ITEM_TYPE_NAME),
interaction: new PalletInteraction(ITEM_TYPE_NAME), setter: propertySetter
setter: propertySetter, }))
})

760
src/modules/rack/RackRenderer.ts_back

@ -1,760 +0,0 @@
import * as THREE from 'three'
import { BufferGeometry } from 'three'
import BaseRenderer from '@/core/base/BaseRenderer.ts'
import { decimalSumBy } from '@/core/ModelUtils'
import Constract from '@/core/Constract.ts'
import Plastic_Rough_JPG from '@/assets/Models/Plastic_Rough.jpg?inline'
import storageBar_PNG from '@/assets/Models/storageBar.png?inline'
import { Material } from 'three/src/materials/Material'
import { InstancedMesh } from 'three/src/objects/InstancedMesh'
//@ts-ignore
import { mergeGeometries } from 'three/addons/utils/BufferGeometryUtils.js'
import type Viewport from '@/core/engine/Viewport.ts'
import type { Object3DLike } from '@/types/ModelTypes.ts'
/**
* 货架货位渲染器
*/
export default class RackRenderer extends BaseRenderer {
static POINT_NAME = 'rack'
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.05
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])
)
}
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.')
}
/**
* 获取物品存放在货架后的位置和旋转角度
* item.dt.storeAt 必须存在, 比如 { item:'货架ID', bay:0, level:1, cell:0 }
*/
getStorePlacement(viewport: Viewport, item: ItemJson): { position: [number, number, number], rotation: [number, number, number] } {
if (!item.dt?.storeAt?.item) {
// 没有定义存储位置,返回空对象
//@ts-ignore
return {}
}
const bay = item.dt?.storeAt?.bay || 0
const level = item.dt?.storeAt?.level || 0
// 暂时不用算格子 const cell = item.dt?.storeAt?.cell || 0
// 目标货架
const rack = viewport.stateManager.findItemById(item.dt.storeAt.item)
const rackWidth = decimalSumBy(rack.dt.bays, (b: any) => b.bayWidth)
const bays = rack.dt.bays
const levelHeights = rack.dt.bays[bay]?.levelHeight
// 局部坐标系下的偏移量
let localX = 0
for (let i = 0; i < bay; i++) {
localX += bays[i]?.bayWidth || 0
}
localX += bays[bay].bayWidth / 2 // 居中
let localY = 0
for (let i = 0; i < level; i++) {
localY += levelHeights[i]
}
// 构建局部偏移向量
const rackPos = new THREE.Vector3(...rack.tf[0])
const offset = new THREE.Vector3(
localX - rackWidth / 2, // 相对坐标从最左边开始,
localY, 0)
// 应用货架的旋转
const q = new THREE.Quaternion()
q.setFromEuler(new THREE.Euler(
THREE.MathUtils.degToRad(rack.tf[1][0]),
THREE.MathUtils.degToRad(rack.tf[1][1]),
THREE.MathUtils.degToRad(rack.tf[1][2])
))
offset.applyQuaternion(q)
const worldPosition = rackPos.clone().add(offset)
return {
position: [
worldPosition.x,
worldPosition.y + this.bottomBarHeight + 0.1, // 加上横梁高度
worldPosition.z
],
rotation: [
// 托盘旋转90度才能放进货架
rack.tf[1][0],
rack.tf[1][1] + 90,
rack.tf[1][2]
]
}
}
updatePoint(item: ItemJson, group: THREE.Group, option?: RendererCudOption): THREE.Group {
group.position.set(item.tf[0][0], item.tf[0][1], item.tf[0][2])
group.rotation.set(
THREE.MathUtils.degToRad(item.tf[1][0]),
THREE.MathUtils.degToRad(item.tf[1][1]),
THREE.MathUtils.degToRad(item.tf[1][2])
)
// group.scale 不允许修改!!
// 禁止缩放,
item.tf[2][0] = item.dt.rackWidth
item.tf[2][1] = item.dt.rackHeight
// 更新放在内部的所有箱子
const subItems = this.tempViewport.runtimeManager.getItemsByRack(item.id)
const viewport = this.tempViewport
if (subItems) {
_.defer(() => {
viewport.stateManager.update(({ getEntity, putEntity, deleteEntity, addEntity }) => {
for (const subItemId of subItems) {
const subItem = getEntity(subItemId)
if (subItem) {
const { position, rotation } = this.getStorePlacement(viewport, subItem)
if (position) {
subItem.tf[0][0] = position[0]
subItem.tf[0][1] = position[1]
subItem.tf[0][2] = position[2]
subItem.tf[1][0] = rotation[0]
subItem.tf[1][1] = rotation[1]
subItem.tf[1][2] = rotation[2]
putEntity(subItem)
}
}
}
})
})
}
return group
}
createPoint(item: ItemJson, option?: RendererCudOption): THREE.Object3D {
// 创建平面几何体
if (!item.dt.bays || !item.dt.rackDepth) {
system.showErrorDialog('RackRenderer field bays / rackDepth is null!')
return null
}
const group = new THREE.Group()
group.name = RackRenderer.POINT_NAME
const rackWidth = decimalSumBy(item.dt.bays, (b: any) => b.bayWidth)
const heights = []
for (let i = 0; i < item.dt.bays.length; i++) {
const bay = item.dt.bays[i]
const bayHeight = decimalSumBy(bay.levelHeight)
heights.push(bayHeight)
}
const rackHeight = _.max(heights)
// // 绘制背景矩形框
// const planeGeometry = new THREE.PlaneGeometry(rackWidth, item.dt.rackDepth)
//
// planeGeometry.rotateX(Math.PI / 2)
//
// const planeMaterial = new THREE.MeshBasicMaterial({
// color: '#9a9090',
// transparent: true, // 启用透明
// opacity: 0.5, // 50%透明度
// depthWrite: false, // 防止深度冲突
// side: THREE.DoubleSide // 双面渲染:ml-citation{ref="5,8" data="citationList"}
// })
// const planeMesh = new THREE.Mesh(planeGeometry, planeMaterial)
// group.add(planeMesh)
//
//
// // 绘制边框
// const lineXLen = rackWidth - this.defaultLineWidth
// const lineYLen = item.dt.rackDepth - 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: '#0d89a5',
// 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)
//
// let lineDistanceX = 0
//
// for (let i = 0; item.dt.bays.length > 1 && i < item.dt.bays.length - 1; i++) {
// const bay = item.dt.bays[i]
// lineDistanceX += bay.bayWidth
// const lineGeometryT = new LineGeometry().setPositions([
// -(lineDistanceX) + (lineXLen / 2), 0, lineYLen / 2,
// -(lineDistanceX) + (lineXLen / 2), 0, -(lineYLen / 2)
// ])
// const lineT = new Line2(lineGeometryT, lineMaterial)
// group.add(lineT as THREE.Object3D)
// }
const meshes = this.createRack(item, option)
meshes.forEach(mesh => {
group.add(mesh)
mesh.instanceMatrix.needsUpdate = true
})
// 设置位置
group.position.set(item.tf[0][0], item.tf[0][1], item.tf[0][2])
group.rotation.set(
THREE.MathUtils.degToRad(item.tf[1][0]),
THREE.MathUtils.degToRad(item.tf[1][1]),
THREE.MathUtils.degToRad(item.tf[1][2])
)
item.dt.rackWidth = rackWidth
item.dt.rackHeight = rackHeight
item.tf[2][0] = item.dt.rackWidth
item.tf[2][1] = item.dt.rackHeight
return group
}
dispose() {
super.dispose()
this.pointMaterial?.dispose()
}
rackVerticalBarWidth = 0.1
rackVerticalBarDepth = 0.08
rackVerticalBarColor = 0xFF35499C
rackVerticalBarGeometry: BufferGeometry = null
rackVerticalBarMaterial: Material = null
rackLinkBarColor = 0xFF35499C
rackLinkBarGeometry: BufferGeometry = null
rackLinkBarMaterial: Material = null
rackHorizontalBarWidth = 0.1
rackHorizontalBarDepth = 0.08
rackHorizontalBarColor = 0xFFF97F27
rackHorizontalBarGeometry: BufferGeometry = null
rackHorizontalBarMaterial: Material = null
bottomBarHeight = 0.2
bottomLinkHeight = 0.2
barSectionPoints = [
{ x: -0.05, y: -0.05 },
{ x: -0.025, y: -0.05 },
{ x: -0.01, y: -0.045 },
{ x: 0.01, y: -0.045 },
{ x: 0.025, y: -0.05 },
{ x: 0.05, y: -0.05 },
{ x: 0.05, y: 0.042 },
{ x: 0.042, y: 0.05 },
{ x: 0.025, y: 0.05 },
{ x: 0.025, y: 0.042 },
{ x: 0.042, y: 0.042 },
{ x: 0.042, y: -0.042 },
{ x: -0.042, y: -0.042 },
{ x: -0.042, y: 0.042 },
{ x: -0.025, y: 0.042 },
{ x: -0.025, y: 0.05 },
{ x: -0.042, y: 0.05 },
{ x: -0.05, y: 0.042 },
{ x: -0.05, y: -0.05 }
]
linkSectionPoints = [
{ x: -0.05, y: -0.05 },
{ x: -0.05, y: 0.05 },
{ x: 0, y: 0.05 },
{ x: 0, y: 0.06 },
{ x: -0.06, y: 0.06 },
{ x: -0.06, y: -0.05 },
{ x: -0.05, y: -0.05 }
]
linkBarSectionPoints = [
{ x: -0.025, y: -0.025 },
{ x: 0.025, y: -0.025 },
{ x: 0.025, y: 0.025 },
{ x: -0.025, y: 0.025 },
{ x: -0.025, y: -0.025 }
]
createVerticalBar(x, y, z, length): THREE.BufferGeometry {
// 创建一个形状 柱子的截面形状
const shape = new THREE.Shape()
shape.moveTo(this.barSectionPoints[0].x, this.barSectionPoints[0].y)
for (let i = 1; i < this.barSectionPoints.length; i++) {
shape.lineTo(this.barSectionPoints[i].x, this.barSectionPoints[i].y)
}
// 拉伸轨迹线
const curve = new THREE.CatmullRomCurve3(
[new THREE.Vector3(0, 0, 0), new THREE.Vector3(0, length, 0)],
false, // 闭合曲线
'catmullrom',
0
)
// 挤出几何图形 参数
const options = {
steps: 1,
bevelEnabled: false,
extrudePath: curve // 设置挤出轨迹
}
// 创建挤出几何体
const geometry = new THREE.ExtrudeGeometry(shape, options)
// 调整uv方便正确贴图
this.resetUVs(geometry)
return geometry
}
createVerticalBarMaterial(): THREE.Material {
let textureLoader = new THREE.TextureLoader()
// 加载纹理
const textureHole = textureLoader.load(storageBar_PNG) // 孔洞
const textureMaterial = textureLoader.load(Plastic_Rough_JPG) // 表面材质
textureHole.repeat.set(10, 18) // X轴重复,Y轴重复
textureMaterial.repeat.set(2, 2) // X轴重复,Y轴重复
// textureHole.offset.set(0.5, 0)
// textureHole.center.set(0.5, 0)
// 必须设置包裹模式为重复
textureHole.wrapS = THREE.RepeatWrapping
textureHole.wrapT = THREE.RepeatWrapping
textureMaterial.wrapS = THREE.RepeatWrapping
textureMaterial.wrapT = THREE.RepeatWrapping
const material = new THREE.MeshPhongMaterial()
material.alphaMap = textureHole
material.normalMap = textureMaterial
material.color.setHex(this.rackVerticalBarColor, 'srgb')
material.specular.setHex(0xff6d6d6d, 'srgb')
material.transparent = true
material.needsUpdate = true
return material
}
createLinkBar(x, y, z, vBarLength, depth, bottomDistance, topDistance): THREE.BufferGeometry {
const bgs: BufferGeometry[] = []
const top = vBarLength - topDistance
// 创建一个形状 柱子的截面形状
const shape = new THREE.Shape()
shape.moveTo(this.linkBarSectionPoints[0].x, this.linkBarSectionPoints[0].y)
for (let i = 1; i < this.linkBarSectionPoints.length; i++) {
shape.lineTo(this.linkBarSectionPoints[i].x, this.linkBarSectionPoints[i].y)
}
// 拉伸轨迹线 横向 底部
const curveHBottom = new THREE.CatmullRomCurve3(
[new THREE.Vector3(0, bottomDistance, 0), new THREE.Vector3(0, bottomDistance, depth)],
false, // 闭合曲线
'catmullrom',
0
)
// 挤出几何图形 参数
const optionsHBottom = {
steps: 1,
bevelEnabled: false,
extrudePath: curveHBottom // 设置挤出轨迹
}
// 拉伸轨迹线 横向 底部
const curveHTop = new THREE.CatmullRomCurve3(
[new THREE.Vector3(0, top, 0), new THREE.Vector3(0, top, depth)],
false, // 闭合曲线
'catmullrom',
0
)
// 挤出几何图形 参数
const optionsHTop = {
steps: 1,
bevelEnabled: false,
extrudePath: curveHTop // 设置挤出轨迹
}
// 创建挤出几何体
const geometryHBottom = new THREE.ExtrudeGeometry(shape, optionsHBottom)
const geometryHTop = new THREE.ExtrudeGeometry(shape, optionsHTop)
bgs.push(geometryHBottom, geometryHTop)
let remainingHeight = vBarLength - bottomDistance - topDistance
// 需要创建斜杆
for (let i = 0; i < Math.floor(remainingHeight / depth); i++) {
// 拉伸轨迹线 斜向
const curveD = new THREE.CatmullRomCurve3(
(i % 2 == 0) ? [new THREE.Vector3(0, bottomDistance + depth * i, 0), new THREE.Vector3(0, bottomDistance + depth * (i + 1), depth)]
: [new THREE.Vector3(0, bottomDistance + depth * (i + 1), 0), new THREE.Vector3(0, bottomDistance + depth * (i), depth)],
false, // 闭合曲线
'catmullrom',
0
)
const optionsD = {
steps: 1,
bevelEnabled: false,
extrudePath: curveD // 设置挤出轨迹
}
const geometryD = new THREE.ExtrudeGeometry(shape, optionsD)
bgs.push(geometryD)
}
if (vBarLength - bottomDistance - topDistance > depth) {
}
// 调整uv方便正确贴图
// this.resetUVs(geometry);
return mergeGeometries(bgs)
}
createLinkBarMaterial(): THREE.Material {
const material = new THREE.MeshPhongMaterial()
material.color.setHex(this.rackLinkBarColor, 'srgb')
material.specular.setHex(0xff6d6d6d, 'srgb')
material.transparent = true
material.needsUpdate = true
return material
}
createHorizontalBar(x, y, z, length): THREE.BufferGeometry {
// 创建一个形状 柱子的截面形状
const shape = new THREE.Shape()
shape.moveTo(this.barSectionPoints[0].x, this.barSectionPoints[0].y)
for (let i = 1; i < this.barSectionPoints.length; i++) {
shape.lineTo(this.barSectionPoints[i].x, this.barSectionPoints[i].y)
}
// 拉伸轨迹线
const curve = new THREE.CatmullRomCurve3(
[new THREE.Vector3(0.05, 0, 0), new THREE.Vector3(length - 0.05, 0, 0)],
false, // 闭合曲线
'catmullrom',
0
)
// 挤出几何图形 参数
const options = {
steps: 1,
bevelEnabled: false,
extrudePath: curve // 设置挤出轨迹
}
// 创建挤出几何体
const geometry = new THREE.ExtrudeGeometry(shape, options)
const linkShapeL = new THREE.Shape()
const linkShapeR = new THREE.Shape()
linkShapeL.moveTo(this.linkSectionPoints[0].x, this.linkSectionPoints[0].y)
linkShapeR.moveTo(this.linkSectionPoints[0].x + (length), this.linkSectionPoints[0].y)
for (let i = 1; i < this.linkSectionPoints.length; i++) {
linkShapeL.lineTo(this.linkSectionPoints[i].x, this.linkSectionPoints[i].y)
linkShapeR.lineTo(this.linkSectionPoints[i].x + (length), this.linkSectionPoints[i].y)
}
// 拉伸轨迹线
const linkCurve = new THREE.CatmullRomCurve3(
[new THREE.Vector3(0, 0, -0.08), new THREE.Vector3(0, 0, 0.08)],
false, // 闭合曲线
'catmullrom',
0
)
// 挤出几何图形 参数
const linkOptions = {
steps: 1,
bevelEnabled: false,
extrudePath: linkCurve // 设置挤出轨迹
}
// 创建挤出几何体
const linkGeometryL = new THREE.ExtrudeGeometry(linkShapeL, linkOptions)
linkGeometryL.rotateZ(-Math.PI / 2)
const linkGeometryR = new THREE.ExtrudeGeometry(linkShapeR, linkOptions)
linkGeometryR.rotateX(-Math.PI)
linkGeometryR.rotateZ(-Math.PI / 2)
// 调整uv方便正确贴图
// this.resetUVs(geometry);
return mergeGeometries([geometry, linkGeometryL, linkGeometryR])
}
createHorizontalBarMaterial(): THREE.Material {
const material = new THREE.MeshPhongMaterial()
material.color.setHex(this.rackHorizontalBarColor, 'srgb')
material.specular.setHex(0xff6d6d6d, 'srgb')
material.transparent = true
material.needsUpdate = true
return material
}
createRack(item: ItemJson, option?: RendererCudOption): InstancedMesh[] {
if (!item.dt.bays || !item.dt.rackDepth) {
system.showErrorDialog('RackRenderer field bays / rackDepth is null!')
return null
}
const rackPoint = {
x: item.tf[0][0],
y: item.tf[0][1],
z: item.tf[0][2]
}
const rackWidth = decimalSumBy(item.dt.bays, (b: any) => b.bayWidth)
const rackDepth = item.dt.rackDepth
const heights = []
for (let i = 0; i < item.dt.bays.length; i++) {
const bay = item.dt.bays[i]
const bayHeight = decimalSumBy(bay.levelHeight)
heights.push(bayHeight)
}
const rackHeight = _.max(heights)
// 计算立住坐标点和长度
const vBarMatrix: { x: number, y: number, z: number, sx: number, sy: number, sz: number, rx: number, ry: number, rz: number, l: number }[] = []
// 计算
const linkBarMatrix: { x: number, y: number, z: number, sx: number, sy: number, sz: number, rx: number, ry: number, rz: number, l: number }[] = []
let distanceX = 0, distanceY = 0
for (let i = -1; i < item.dt.bays.length; i++) {
if (i >= 0) {
const bay = item.dt.bays[i]
distanceX += bay.bayWidth
}
vBarMatrix.push({
x: distanceX - rackWidth / 2,
y: 0,
z: -rackDepth / 2,
sx: 0.8,
sy: 1,
sz: 1,
rx: 0,
ry: Math.PI / 2,
rz: 0,
l: rackHeight
})
vBarMatrix.push({
x: distanceX - rackWidth / 2,
y: 0,
z: item.dt.rackDepth - rackDepth / 2,
sx: 0.8,
sy: 1,
sz: 1,
rx: 0,
ry: -Math.PI / 2,
rz: 0,
l: rackHeight
})
linkBarMatrix.push({
x: distanceX - rackWidth / 2,
y: 0,
z: i % 2 == 0 ? (item.dt.rackDepth - rackDepth / 2) : -rackDepth / 2,
sx: 1,
sy: 1,
sz: 1,
rx: 0,
ry: i % 2 == 0 ? Math.PI : 0,
rz: 0,
l: rackHeight
})
}
// 计算横梁数量
const hBarMatrix: { x: number, y: number, z: number, sx: number, sy: number, sz: number, rx: number, ry: number, rz: number, l: number }[] = []
distanceX = 0
for (let i = 0; i < item.dt.bays.length; i++) {
distanceY = this.bottomBarHeight
const bay = item.dt.bays[i]
for (let j = 0; j < bay.levelHeight.length; j++) {
const levelHeight = bay.levelHeight[j]
if (distanceY <= 0) {
continue
}
hBarMatrix.push({
x: distanceX - rackWidth / 2,
y: distanceY,
z: -rackDepth / 2,
sx: 1,
sy: 0.8,
sz: 1,
rx: Math.PI / 2,
ry: 0,
rz: 0,
l: bay.bayWidth
})
hBarMatrix.push({
x: distanceX - rackWidth / 2,
y: distanceY,
z: item.dt.rackDepth - rackDepth / 2,
sx: 1,
sy: 0.8,
sz: 1,
rx: -Math.PI / 2,
ry: 0,
rz: 0,
l: bay.bayWidth
})
distanceY += levelHeight
}
distanceX += bay.bayWidth
}
const meshes: InstancedMesh[] = []
if (vBarMatrix.length > 0) {
if (!this.rackVerticalBarGeometry) {
this.rackVerticalBarGeometry = this.createVerticalBar(vBarMatrix[0].x, vBarMatrix[0].y, vBarMatrix[0].z, vBarMatrix[0].l)
}
if (!this.rackVerticalBarMaterial) {
this.rackVerticalBarMaterial = this.createVerticalBarMaterial()
}
const dummy = new THREE.Object3D()
const vBarMesh = new THREE.InstancedMesh(this.rackVerticalBarGeometry, this.rackVerticalBarMaterial, vBarMatrix.length)
for (let i = 0; i < vBarMatrix.length; i++) {
const vp = vBarMatrix[i]
dummy.position.set(vp.x, vp.y, vp.z)
dummy.rotation.set(vp.rx, vp.ry, vp.rz)
dummy.scale.set(vp.sx, vp.sy, vp.sz)
dummy.updateMatrix()
vBarMesh.setMatrixAt(i, dummy.matrix)
}
meshes.push(vBarMesh)
}
if (linkBarMatrix.length > 0) {
if (!this.rackLinkBarGeometry) {
this.rackLinkBarGeometry = this.createLinkBar(linkBarMatrix[0].x, linkBarMatrix[0].y, linkBarMatrix[0].z, rackHeight, item.dt.rackDepth, this.bottomLinkHeight, 0.2)
}
if (!this.rackLinkBarMaterial) {
this.rackLinkBarMaterial = this.createLinkBarMaterial()
}
const dummy = new THREE.Object3D()
const linkBarMesh = new THREE.InstancedMesh(this.rackLinkBarGeometry, this.rackLinkBarMaterial, linkBarMatrix.length)
for (let i = 0; i < linkBarMatrix.length; i++) {
const lp = linkBarMatrix[i]
dummy.position.set(lp.x, lp.y, lp.z)
dummy.rotation.set(lp.rx, lp.ry, lp.rz)
dummy.scale.set(lp.sx, lp.sy, lp.sz)
dummy.updateMatrix()
linkBarMesh.setMatrixAt(i, dummy.matrix)
}
meshes.push(linkBarMesh)
}
if (hBarMatrix.length > 0) {
if (!this.rackHorizontalBarGeometry) {
this.rackHorizontalBarGeometry = this.createHorizontalBar(hBarMatrix[0].x, hBarMatrix[0].y, hBarMatrix[0].z, hBarMatrix[0].l)
}
if (!this.rackHorizontalBarMaterial) {
this.rackHorizontalBarMaterial = this.createHorizontalBarMaterial()
}
const dummy = new THREE.Object3D()
const hBarMesh = new THREE.InstancedMesh(this.rackHorizontalBarGeometry, this.rackHorizontalBarMaterial, hBarMatrix.length)
for (let i = 0; i < hBarMatrix.length; i++) {
const hp = hBarMatrix[i]
dummy.position.set(hp.x, hp.y, hp.z)
dummy.rotation.set(hp.rx, hp.ry, hp.rz)
dummy.scale.set(hp.sx, hp.sy, hp.sz)
dummy.updateMatrix()
hBarMesh.setMatrixAt(i, dummy.matrix)
}
meshes.push(hBarMesh)
}
return meshes
}
resetUVs(geometry: THREE.ExtrudeGeometry) {
if (geometry == undefined) return
const pos = geometry.getAttribute('position'),
nor = geometry.getAttribute('normal'),
uvs = geometry.getAttribute('uv')
for (let i = 0; i < pos.count; i++) {
let x = 0, y = 0
const nx = Math.abs(nor.getX(i)), ny = Math.abs(nor.getY(i)), nz = Math.abs(nor.getZ(i))
// if facing X
if (nx >= ny && nx >= nz) {
x = pos.getZ(i)
y = pos.getY(i)
}
// if facing Y
if (ny >= nx && ny >= nz) {
x = pos.getX(i)
y = pos.getZ(i)
}
// if facing Z
if (nz >= nx && nz >= ny) {
x = pos.getX(i)
y = pos.getY(i)
}
uvs.setXY(i, x, y)
}
}
}

13
src/modules/rack/index.ts

@ -1,13 +1,12 @@
import { defineModule } from '@/core/manager/ModuleManager.ts' import { defineModule } from '@/core/manager/ModuleManager.ts'
import RackRenderer from './RackRenderer.ts' import RackRenderer from './RackRenderer.ts'
import RackInteraction from './RackInteraction.ts' import RackInteraction from './RackInteraction.ts'
import propertySetter from "@/modules/rack/RackPropertySetter.ts"; import propertySetter from '@/modules/rack/RackPropertySetter.ts'
export const ITEM_TYPE_NAME = 'rack' export const ITEM_TYPE_NAME = 'rack'
export default defineModule({ export default defineModule(ITEM_TYPE_NAME, () => ({
name: ITEM_TYPE_NAME, renderer: new RackRenderer(ITEM_TYPE_NAME),
renderer: new RackRenderer(ITEM_TYPE_NAME), interaction: new RackInteraction(ITEM_TYPE_NAME),
interaction: new RackInteraction(ITEM_TYPE_NAME), setter: propertySetter
setter: propertySetter, }))
})

13
src/modules/shuttle_rack/index.ts

@ -1,13 +1,12 @@
import { defineModule } from '@/core/manager/ModuleManager.ts' import { defineModule } from '@/core/manager/ModuleManager.ts'
import ShuttleRackRenderer from './ShuttleRackRenderer.ts' import ShuttleRackRenderer from './ShuttleRackRenderer.ts'
import ShuttleRackInteraction from './ShuttleRackInteraction.ts' import ShuttleRackInteraction from './ShuttleRackInteraction.ts'
import propertySetter from "./ShuttleRackPropertySetter.ts"; import propertySetter from './ShuttleRackPropertySetter.ts'
export const ITEM_TYPE_NAME = 'shuttle_rack' export const ITEM_TYPE_NAME = 'shuttle_rack'
export default defineModule({ export default defineModule(ITEM_TYPE_NAME, () => ({
name: ITEM_TYPE_NAME, renderer: new ShuttleRackRenderer(ITEM_TYPE_NAME),
renderer: new ShuttleRackRenderer(ITEM_TYPE_NAME), interaction: new ShuttleRackInteraction(ITEM_TYPE_NAME),
interaction: new ShuttleRackInteraction(ITEM_TYPE_NAME), setter: propertySetter
setter: propertySetter, }))
})

7
src/modules/tote/index.ts

@ -5,9 +5,8 @@ import propertySetter from './TotePropertySetter.ts'
export const ITEM_TYPE_NAME = 'tote' export const ITEM_TYPE_NAME = 'tote'
export default defineModule({ export default defineModule(ITEM_TYPE_NAME, () => ({
name: ITEM_TYPE_NAME,
renderer: new ToteRenderer(ITEM_TYPE_NAME), renderer: new ToteRenderer(ITEM_TYPE_NAME),
interaction: new ToteInteraction(ITEM_TYPE_NAME), interaction: new ToteInteraction(ITEM_TYPE_NAME),
setter: propertySetter, setter: propertySetter
}) }))

13
src/modules/way/index.ts

@ -1,13 +1,12 @@
import { defineModule } from '@/core/manager/ModuleManager.ts' import { defineModule } from '@/core/manager/ModuleManager.ts'
import WayRenderer from './WayRenderer.ts' import WayRenderer from './WayRenderer.ts'
import WayInteraction from './WayInteraction.ts' import WayInteraction from './WayInteraction.ts'
import propertySetter from "@/modules/way/WayPropertySetter.ts"; import propertySetter from '@/modules/way/WayPropertySetter.ts'
export const ITEM_TYPE_NAME = 'way' export const ITEM_TYPE_NAME = 'way'
export default defineModule({ export default defineModule(ITEM_TYPE_NAME, () => ({
name: ITEM_TYPE_NAME, renderer: new WayRenderer(ITEM_TYPE_NAME),
renderer: new WayRenderer(ITEM_TYPE_NAME), interaction: new WayInteraction(ITEM_TYPE_NAME),
interaction: new WayInteraction(ITEM_TYPE_NAME), setter: propertySetter
setter: propertySetter, }))
})

3
src/types/global.d.ts

@ -9,6 +9,5 @@ declare global {
const _: _ const _: _
const system: System const system: System
const worldModel: WorldModel
const CurrentMouseInfo: CurrentMouseInfo const CurrentMouseInfo: CurrentMouseInfo
} }

Loading…
Cancel
Save