Browse Source

基本容器符合尺寸容器要求

master
修宁 6 months ago
parent
commit
9a6e660c14
  1. BIN
      src/assets/Models/Pallet.glb
  2. BIN
      src/assets/Models/Pallet.jpg
  3. BIN
      src/assets/Models/Platistic1.jpg
  4. 319
      src/core/manager/DragManager.ts
  5. 83
      src/core/manager/MouseMoveManager.ts
  6. 436
      src/core/manager/SelectManager.ts
  7. 58
      src/modules/tote/ToteRenderer.ts

BIN
src/assets/Models/Pallet.glb

Binary file not shown.

BIN
src/assets/Models/Pallet.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 706 KiB

BIN
src/assets/Models/Platistic1.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 MiB

319
src/core/manager/DragManager.ts

@ -0,0 +1,319 @@
import * as THREE from 'three'
import type Viewport from '@/core/engine/Viewport.ts'
import { getClosestObject } from '@/core/ModelUtils.ts'
import EventBus from '@/runtime/EventBus.ts'
import type { Object3DLike } from '@/types/ModelTypes.ts'
import InstancePointManager, { PointManageWrap } from '@/core/manager/InstancePointManager.ts'
import { LineManageWrap } from '@/core/manager/LineSegmentManager.ts'
/**
* ThreeJS X/Z
*/
export default class DragControl {
private viewport: Viewport
private _is_enabled: boolean = true
private domElement: HTMLElement
private isPointerDown: boolean = false
private dragStartMouse: THREE.Vector2 = new THREE.Vector2()
private checkStateInterval: number | null = null
private dragShadowsGroup: THREE.Group | null = null
private dragDelayTimeout: number | null = null
private static readonly SHADOW_MATERIAL = new THREE.MeshBasicMaterial({
color: 0x222222,
transparent: true,
opacity: 0.5,
depthWrite: false,
side: THREE.DoubleSide
})
public isDragging: boolean = false
init(viewport: Viewport): void {
this.viewport = viewport
const domElement = this.viewport.renderer.domElement
this.domElement = domElement
domElement.addEventListener('pointerdown', this.onPointerDown)
domElement.addEventListener('pointermove', this.onPointerMove)
domElement.addEventListener('pointerup', this.onPointerUp)
domElement.addEventListener('pointerleave', this.onPointerLeave)
domElement.style.cursor = 'auto'
}
/**
*
*/
dispose(): void {
if (this.domElement) {
this.domElement.removeEventListener('pointermove', this.onPointerMove)
this.domElement.removeEventListener('pointerdown', this.onPointerDown)
this.domElement.removeEventListener('pointerup', this.onPointerUp)
this.domElement.removeEventListener('pointerleave', this.onPointerLeave)
}
this.cleanupDrag()
this.viewport = null
}
/**
* pointerdown
*/
private onPointerDown = (event: PointerEvent): void => {
if (!this.enabled) return
const mouse = this.getMousePosition(event.clientX, event.clientY)
const intersected = this.getIntersectedDraggableObject(mouse)
if (!intersected) return
this.viewport.controls.enabled = false
// 设置定时器:0.1秒后才抓取拖拽
this.dragDelayTimeout = window.setTimeout(() => {
this.isPointerDown = true
this.dragStartMouse.set(intersected.position.x, intersected.position.z)
let selectedObjects = [intersected]
const multiSelected = this.viewport.state.multiSelectedObjects
if (multiSelected.length > 0 && multiSelected.includes(intersected)) {
selectedObjects = multiSelected
}
this.createShadows(selectedObjects)
this.domElement.style.cursor = 'grabbing'
this.checkStateInterval = setInterval(() => {
if (isNaN(CurrentMouseInfo.x) || isNaN(CurrentMouseInfo.z) || !this.isPointerDown) {
this.cancelDrag()
}
}, 100) // 每100毫秒检查一次状态, 鼠标移出要主动清理
}, 100) // 0.1秒延迟抓取
}
/**
* pointermove
*/
private onPointerMove = (event: PointerEvent): void => {
if (!this.enabled || !this.domElement) return
if (!isNaN(this.dragStartMouse.x) && !isNaN(this.dragStartMouse.y) && this.dragShadowsGroup) {
this.isDragging = true
this.domElement.style.cursor = 'grabbing'
this.updateShadows(new THREE.Vector2(CurrentMouseInfo.x, CurrentMouseInfo.z))
} else {
// 射线方法修改 ==========================
const mouse = this.getMousePosition(event.clientX, event.clientY)
const intersected = this.getIntersectedDraggableObject(mouse)
// =====================================
// const ids = this.viewport.itemFindManager.getItemsByPosition(CurrentMouseInfo.x, CurrentMouseInfo.z)
this.domElement.style.cursor = intersected ? 'grab' : 'auto'
}
}
/**
* pointerup
*/
private onPointerUp = (event: PointerEvent): void => {
if (this.isDragging) {
const startPos = this.dragStartMouse.clone()
const targetPos = new THREE.Vector2(CurrentMouseInfo.x, CurrentMouseInfo.z)
if (startPos && targetPos && !_.isNaN(startPos.x) && !_.isNaN(startPos.y)) {
this.dragComplete(startPos, targetPos)
}
}
this.cleanupDrag()
}
/**
*
*/
private cleanupDrag(): void {
if (this.domElement) {
this.domElement.style.cursor = 'auto'
}
this.isDragging = false
this.isPointerDown = false
this.dragStartMouse.set(NaN, NaN)
this.removeShadows()
if (this.viewport) {
this.viewport.controls.enabled = true
}
if (this.dragDelayTimeout !== null) {
clearTimeout(this.dragDelayTimeout)
this.dragDelayTimeout = null
}
if (this.checkStateInterval) {
clearInterval(this.checkStateInterval)
this.checkStateInterval = null
}
}
/**
*
*/
private getMousePosition(clientX: number, clientY: number): THREE.Vector2 {
const rect = this.domElement.getBoundingClientRect()
return new THREE.Vector2(
((clientX - rect.left) / rect.width) * 2 - 1,
((clientY - rect.top) / rect.height) * -2 + 1
)
}
/**
* 线
*/
private getIntersectedDraggableObject(mouse: THREE.Vector2): Object3DLike | undefined {
const raycaster = new THREE.Raycaster()
raycaster.setFromCamera(mouse, this.viewport.camera)
const draggableObjects = this.viewport.entityManager._draggableObjects || []
const intersects = raycaster.intersectObjects(draggableObjects, true)
if (intersects.length > 0) {
return getClosestObject(this.viewport, intersects[0].object, intersects[0].instanceId)
}
}
/**
*
*/
private createShadows(objects: Object3DLike[]): void {
this.removeShadows()
this.dragShadowsGroup = new THREE.Group()
for (const obj of objects) {
if (_.isNil(_.get(obj, 'userData.entityId'))) {
console.error(`Object ${obj.name} missing entityId`)
continue
}
// 克隆对象的几何体和材质
// const shadowBox = obj.clone()
let box: THREE.Box3
if (obj instanceof THREE.Object3D) {
box = new THREE.Box3().setFromObject(obj)
} else if (obj instanceof PointManageWrap) {
box = obj.createBox3()
}
const size = new THREE.Vector3()
box.getSize(size)
const geometry = new THREE.PlaneGeometry(size.x, size.z)
const shadowBox = new THREE.Mesh(geometry, DragControl.SHADOW_MATERIAL)
shadowBox.position.copy(obj.position)
shadowBox.rotation.x = -Math.PI / 2
shadowBox.userData = {
isShadow: true,
entityId: obj.userData.entityId,
originPosition: obj.position.clone() // 保存原始位置
}
this.dragShadowsGroup.add(shadowBox)
}
this.viewport.scene.add(this.dragShadowsGroup)
}
/**
*
*/
private removeShadows(): void {
if (this.dragShadowsGroup) {
console.log('removeShadows')
this.viewport.scene.remove(this.dragShadowsGroup)
this.dragShadowsGroup = null
}
}
/**
* X/Z
*/
private updateShadows(newPosition: THREE.Vector2): void {
if (!this.dragShadowsGroup) return
// 计算新位置与拖拽开始位置的偏移量
const offsetX = newPosition.x - this.dragStartMouse.x
const offsetZ = newPosition.y - this.dragStartMouse.y
for (let i = 0; i < this.dragShadowsGroup.children.length; i++) {
const shadow = this.dragShadowsGroup.children[i] as THREE.Mesh
if (!shadow.userData.originPosition) {
console.error(`Shadow ${shadow.name} does not have originPosition`)
continue
}
const newPosX = shadow.userData.originPosition.x + offsetX
const newPosZ = shadow.userData.originPosition.z + offsetZ
shadow.position.set(newPosX, shadow.userData.originPosition.y, newPosZ) // 锁定 Y 轴高度
// console.log(`Updating shadow ${shadow.name} position with offset:`, offsetX, offsetZ)
}
}
private dragComplete = (startPos: THREE.Vector2, targetPos: THREE.Vector2): void => {
// console.log(`Drag completed from ${startPos.toArray()} to ${targetPos.toArray()}`)
this.viewport.stateManager.update(({ getEntity, putEntity, deleteEntity, addEntity }) => {
for (const object of this.dragShadowsGroup.children) {
const entityId = object.userData.entityId
if (entityId) {
const entity = getEntity(entityId)
// 更新实体位置
entity.tf[0][0] = object.position.x
entity.tf[0][2] = object.position.z
putEntity(entity)
} else {
system.showErrorDialog('not found entity')
}
}
})
// EventBus.dispatch('multiSelectedObjectsChanged', {
// multiSelectedObjects: this.viewport.state.multiSelectedObjects
// })
// EventBus.dispatch('selectedObjectPropertyChanged', {})
this.cleanupDrag()
}
/**
* pointerleave
*/
private onPointerLeave = (_event: PointerEvent): void => {
this.cancelDrag()
}
/**
*
*/
cancelDrag(): void {
this.cleanupDrag()
}
/**
* /
*/
public set enabled(value: boolean) {
this._is_enabled = value
if (!value) {
this.cleanupDrag()
}
}
public get enabled(): boolean {
return this._is_enabled
}
}

83
src/core/manager/MouseMoveManager.ts

@ -0,0 +1,83 @@
import type Viewport from '@/core/engine/Viewport'
import * as THREE from 'three'
let pmFn, otFn, lvFn
/**
* designer.mousePos
*/
export default class MouseMoveManager {
viewport: Viewport
canvas: HTMLCanvasElement
constructor() {
}
init(viewport: Viewport) {
this.viewport = viewport
this.canvas = this.viewport.renderer.domElement as HTMLCanvasElement
pmFn = this.mouseMove.bind(this)
otFn = this.mouseLv.bind(this)
lvFn = this.mouseLv.bind(this)
this.canvas.addEventListener('pointermove', pmFn)
this.canvas.addEventListener('pointerout', otFn)
this.canvas.addEventListener('mouseleave', lvFn)
}
dispose() {
this.canvas.removeEventListener('pointermove', pmFn)
pmFn = undefined
this.canvas.removeEventListener('pointerout', otFn)
otFn = undefined
this.canvas.removeEventListener('mouseleave', lvFn)
lvFn = undefined
}
mouseLv(event: MouseEvent) {
this.viewport.state.mouse.x = NaN
this.viewport.state.mouse.z = NaN
window['CurrentMouseInfo'] = {
x: NaN,
z: NaN,
isShiftKey: false,
isCtrlKey: false,
isAltKey: false,
isMetaKey: false
}
}
mouseMove = _.throttle(function(this: MouseMoveManager, event: MouseEvent) {
const pointv = new THREE.Vector2()
pointv.x = event.offsetX / this.viewport.renderer.domElement.offsetWidth
pointv.y = event.offsetY / this.viewport.renderer.domElement.offsetHeight
const mouse = new THREE.Vector2()
mouse.set((pointv.x * 2) - 1, -(pointv.y * 2) + 1)
// 当前鼠标所在的点
const point = this.viewport.getClosestIntersection(event)
if (!point) {
return
}
this.viewport.state.mouse.x = point.x
this.viewport.state.mouse.z = point.z
window['CurrentMouseInfo'] = {
viewport: this.viewport,
x: point.x,
z: point.z,
isShiftKey: event.shiftKey,
isCtrlKey: event.ctrlKey,
isAltKey: event.altKey,
isMetaKey: event.metaKey,
mouse: mouse
}
}, 1)
animate(): void {
}
}

436
src/core/manager/SelectManager.ts

@ -0,0 +1,436 @@
import * as THREE from 'three'
import type Viewport from '@/core/engine/Viewport'
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 EventBus from '@/runtime/EventBus'
import { markRaw } from 'vue'
import { getSetter } from '@/core/manager/ModuleManager.ts'
import Constract from '@/core/Constract.ts'
import type { Object3DLike } from '@/types/ModelTypes.ts'
import { PointManageWrap } from '@/core/manager/InstancePointManager.ts'
import { getAABBox, getOBBox } from '@/core/ModelUtils.ts'
/**
*
*/
export default class SelectManager {
viewport: Viewport
/**
* 线
*/
yellowMaterial: LineMaterial = new LineMaterial({ color: 0xffff00, linewidth: 3 })
/**
* 线
*/
redMaterial: LineMaterial = new LineMaterial({ color: 0xff0000, linewidth: 3 })
/**
*
*/
rectMaterial: THREE.MeshBasicMaterial = new THREE.MeshBasicMaterial({
color: 0x000000,
opacity: 0.3,
transparent: true
})
/**
*
*/
rectangle: THREE.Mesh | null = null
/**
* 线
*/
selectionBox: Line2
/**
* , viewport.renderer.domElement
*/
canvas: HTMLCanvasElement
/**
*
*/
recStartPos: THREE.Vector3 | null
clickTime: number | null = null
constructor() {
}
init(viewport: Viewport) {
this.viewport = viewport
this.canvas = this.viewport.renderer.domElement as HTMLCanvasElement
// 监听 shift 按住之后的矩形
this.canvas.addEventListener('pointerdown', this.onMouseDown)
this.canvas.addEventListener('pointermove', this.onMouseMove)
this.canvas.addEventListener('pointerup', this.onMouseUp)
EventBus.on('selectedObjectChanged', this.updateSelectionBox)
EventBus.on('multiSelectedObjectsChanged', this.updateMultiSelectionBoxes)
EventBus.on('selectedObjectPropertyChanged', this.updateSelectionBox)
// EventBus.on('multiselectedObjectChanged', this.updateMultiSelectionBoxes)
}
redSelectionGroup = new THREE.Group()
updateMultiSelectionBoxes = () => {
const multiSelectedObjects = this.viewport.state.multiSelectedObjects
// 为所有多选对象创建包围盒线框
this.clearRedSelectionBoxes()
if (!multiSelectedObjects || multiSelectedObjects.length === 0) {
return
}
for (const object of multiSelectedObjects) {
if (object.userData.entityId) {
this.createRedSelectionBox(object)
}
}
}
// 取消红选
cancelMultiSelect() {
this.viewport.state.multiSelectedObjects = []
this.viewport.state.multiSelectedItems = []
this.viewport.state.multiSelectedEntityIds = []
EventBus.dispatch('multiSelectedObjectsChanged', {
viewport: markRaw(this.viewport),
multiSelectedObjects: [],
multiSelectedItems: [],
multiSelectedEntityIds: []
})
}
// 取消黄选
cancelSelect() {
this.viewport.state.selectedObject = null
this.viewport.state.selectedItem = null
this.viewport.state.selectedEntityId = null
this.viewport.state.selectedObjectSetter = null
EventBus.dispatch('selectedObjectChanged', {
viewport: markRaw(this.viewport),
selectedObject: null,
selectedItem: null,
selectedEntityId: null,
selectedObjectSetter: null
})
}
// 根据 entityId 选择对象
selectById(entityId: string | null) {
if (!entityId) {
this.viewport.state.selectedObject = null
this.viewport.state.selectedItem = null
this.viewport.state.selectedEntityId = null
this.viewport.state.selectedObjectSetter = null
EventBus.dispatch('selectedObjectChanged', {
viewport: markRaw(this.viewport),
selectedObject: null,
selectedItem: null,
selectedEntityId: null,
selectedObjectSetter: null
})
return
}
const item = this.viewport.entityManager.findItemById(entityId)
const object = this.viewport.entityManager.findObjectById(entityId)
const itemTypeName = item.t
if (item.dt.protected !== true) {
this.viewport.state.selectedObject = markRaw(object)
this.viewport.state.selectedItem = markRaw(item)
this.viewport.state.selectedEntityId = entityId
this.viewport.state.selectedObjectSetter = getSetter(itemTypeName)
EventBus.dispatch('selectedObjectChanged', {
viewport: markRaw(this.viewport),
selectedObject: this.viewport.state.selectedObject,
selectedItem: this.viewport.state.selectedItem,
selectedEntityId: this.viewport.state.selectedEntityId,
selectedObjectSetter: this.viewport.state.selectedObjectSetter
})
}
}
// 多选对象
multiSelectByIds(entityIds: string[]) {
// 遍历找到的对象,添加到多选对象中
const multiSelectedObjects = []
const multiSelectedItems = []
const multiSelectedEntityIds = []
for (const entityId of entityIds) {
const object = this.viewport.entityManager.findObjectById(entityId)
if (object.userData.entityId && object.userData.t) {
const item = this.viewport.entityManager.findItemById(object.userData.entityId)
if (item && item.dt.protected !== true) {
multiSelectedObjects.push(object)
multiSelectedItems.push(item)
multiSelectedEntityIds.push(object.userData.entityId)
}
}
}
this.viewport.state.multiSelectedObjects = markRaw(multiSelectedObjects)
this.viewport.state.multiSelectedItems = markRaw(multiSelectedItems)
this.viewport.state.multiSelectedEntityIds = multiSelectedEntityIds
EventBus.dispatch('multiSelectedObjectsChanged', {
viewport: markRaw(this.viewport),
multiSelectedObjects: this.viewport.state.multiSelectedObjects,
multiSelectedItems: this.viewport.state.multiSelectedItems,
multiSelectedEntityIds: this.viewport.state.multiSelectedEntityIds
})
}
// 清除之前的红色包围盒线框
private clearRedSelectionBoxes() {
if (this.redSelectionGroup.children.length > 0) {
for (const child of this.redSelectionGroup.children) {
this.redSelectionGroup.remove(child)
}
}
this.viewport.scene.remove(this.redSelectionGroup)
this.redSelectionGroup = new THREE.Group()
this.viewport.scene.add(this.redSelectionGroup)
}
// 创建红选包围盒
private createRedSelectionBox(object: Object3DLike) {
// 如果对象没有 entityId,则不创建包围盒线框
if (!object.userData.entityId) {
return
}
let box: THREE.Box3
if (object instanceof PointManageWrap) {
box = object.createBox3()
} else if (object instanceof THREE.Object3D) {
box = new THREE.Box3().setFromObject(object)
}
const min = box.min
const max = box.max
const corners = [
new THREE.Vector3(min.x - Constract.RED_EXPAND_AMOUNT, max.y + Constract.RED_EXPAND_AMOUNT, min.z - Constract.RED_EXPAND_AMOUNT),
new THREE.Vector3(max.x + Constract.RED_EXPAND_AMOUNT, max.y + Constract.RED_EXPAND_AMOUNT, min.z - Constract.RED_EXPAND_AMOUNT),
new THREE.Vector3(max.x + Constract.RED_EXPAND_AMOUNT, max.y + Constract.RED_EXPAND_AMOUNT, max.z + Constract.RED_EXPAND_AMOUNT),
new THREE.Vector3(min.x - Constract.RED_EXPAND_AMOUNT, max.y + Constract.RED_EXPAND_AMOUNT, max.z + Constract.RED_EXPAND_AMOUNT)
]
// 构建矩形边框(4 条边)
const positions = []
for (let i = 0; i < 4; i++) {
const p1 = corners[i]
const p2 = corners[(i + 1) % 4]
positions.push(p1.x, p1.y, p1.z)
positions.push(p2.x, p2.y, p2.z)
}
// 创建几何体
const lineGeom = new LineGeometry()
const vertices = new Float32Array(positions)
lineGeom.setPositions(vertices)
const selectionBox = new Line2(lineGeom, this.redMaterial)
selectionBox.computeLineDistances()
this.redSelectionGroup.add(selectionBox)
}
// 更新选中对象的包围盒线框
private updateSelectionBox = () => {
this.clearSelectionBox()
const item = this.viewport.state.selectedItem
if (!item) {
return
}
// 构造 positions 数组
const edgePositions = getOBBox(item) // getOBBox(item) // getAABBox(item)
const positions = []
for (let i = 0; i < edgePositions.length; i += 2) {
const p1 = edgePositions[i]
const p2 = edgePositions[i + 1]
positions.push(p1.x, p1.y, p1.z)
positions.push(p2.x, p2.y, p2.z)
}
const lineGeom = new LineGeometry().setPositions(new Float32Array(positions))
const selectionBox = new Line2(lineGeom, this.yellowMaterial)
selectionBox.computeLineDistances()
selectionBox.scale.set(1, 1, 1)
this.selectionBox = selectionBox
console.log('selectedItem', this.viewport.state.selectedItem)
this.viewport.scene.add(selectionBox)
}
dispose() {
this.canvas.removeEventListener('pointerdown', this.onMouseDown)
this.canvas.removeEventListener('pointermove', this.onMouseMove)
this.canvas.removeEventListener('pointerup', this.onMouseUp)
// 销毁选择工具
this.clearSelectionBox()
this.disposeRect()
this.clearRedSelectionBoxes()
}
// 清除当前选中对象的包围盒线框
private clearSelectionBox = () => {
if (this.selectionBox) {
this.viewport.scene.remove(this.selectionBox)
this.selectionBox.geometry.dispose()
this.selectionBox = null
}
}
private createRectangle = () => {
if (this.rectangle !== null) {
this.disposeRect()
}
if (this.recStartPos) {
// 创建矩形
this.rectangle = new THREE.Mesh(
new THREE.PlaneGeometry(0.001, 0.001),
this.rectMaterial
)
this.rectangle.name = 'selectRectangle'
this.rectangle.rotation.x = -Math.PI / 2 // 关键!让平面正对相机
this.rectangle.position.set(
this.recStartPos.x,
this.recStartPos.y,
this.recStartPos.z
)
this.viewport.scene.add(this.rectangle)
}
}
private updateRectangle = (position: THREE.Vector3) => {
if (!this.rectangle || !this.recStartPos) return
// console.log('updateRectangle', this.recStartPos, position)
const width = position.x - this.recStartPos.x
const height = position.z - this.recStartPos.z
const newWidth = Math.abs(width)
const newHeight = Math.abs(height)
// 清理旧几何体
this.rectangle.geometry.dispose()
this.rectangle.geometry = new THREE.PlaneGeometry(newWidth, newHeight)
this.rectangle.position.set(
this.recStartPos.x + width / 2,
this.recStartPos.y,
this.recStartPos.z + height / 2
)
}
private onMouseDown = (event: MouseEvent) => {
if (event.shiftKey) {
// 记录鼠标按下位置
this.recStartPos = this.viewport.getClosestIntersection(event)
this.createRectangle()
this.viewport.controls.enabled = false // 禁用控制器
} else {
// 为 click 事件添加处理逻辑
this.clickTime = Date.now()
}
}
private onMouseMove = (event: MouseEvent) => {
if (!this.recStartPos) {
this.disposeRect()
}
// 更新矩形大小或重新生成矩形
const position = this.viewport.getClosestIntersection(event)
if (!position) return
this.updateRectangle(position)
}
private onMouseUp = (event: MouseEvent) => {
this.disposeRect()
const clickTime = this.clickTime
this.clickTime = null
if (Date.now() - clickTime < 200) {
// 如果是点击事件,触发选中逻辑
const objects: Object3DLike[] = this.viewport.entityManager.getObjectByCanvasMouse(event)
if (objects.length > 0 && objects[0]?.userData?.entityId && objects[0]?.userData?.createType !== 'line') {
console.log('mouseClick', objects)
const object = objects[0]
this.selectById(object.userData.entityId)
} else {
// 如果没有选中任何对象,清除选中状态
this.selectById(null)
}
}
}
private disposeRect = () => {
if (this.rectangle !== null) {
// 查找在这个矩形内的所有有效业务对象,并将他们添加进 viewport.state.multiSelectedObjects
this.calcRectangleObjectToState()
this.viewport.scene.remove(this.rectangle)
this.rectangle.geometry.dispose()
this.rectangle = null
}
this.recStartPos = null
this.viewport.controls.enabled = true // 启用控制器
}
private calcRectangleObjectToState = () => {
if (!this.rectangle || !this.recStartPos) return
// 获取矩形的包围盒
const box = new THREE.Box3().setFromObject(this.rectangle)
// 获取盒子的 startX, startZ, endX, endZ
const startX = box.min.x
const startZ = box.min.z
const endX = box.max.x
const endZ = box.max.z
// 查找所有在矩形内的对象
const ids = this.viewport.itemFindManager.getItemsByRect(startX, startZ, endX, endZ)
// 清空之前的多选对象
this.viewport.state.multiSelectedObjects = []
// 遍历找到的对象,添加到多选对象中
const multiSelectedObjects = []
const multiSelectedItems = []
const multiSelectedEntityIds = []
for (const id of ids) {
const object = this.viewport.entityManager.findObjectById(id)
if (object.userData.entityId && object.userData.t) {
const item = this.viewport.entityManager.findItemById(object.userData.entityId)
if (item && item.dt.protected !== true) {
multiSelectedObjects.push(object)
multiSelectedItems.push(item)
multiSelectedEntityIds.push(id)
}
}
}
// 触发多选对象更新事件
this.viewport.state.multiSelectedObjects = markRaw(multiSelectedObjects)
this.viewport.state.multiSelectedItems = markRaw(multiSelectedItems)
this.viewport.state.multiSelectedEntityIds = multiSelectedEntityIds
EventBus.dispatch('multiSelectedObjectsChanged', {
viewport: markRaw(this.viewport),
multiSelectedObjects: this.viewport.state.multiSelectedObjects,
multiSelectedItems: this.viewport.state.multiSelectedItems,
multiSelectedEntityIds: this.viewport.state.multiSelectedEntityIds
})
}
}

58
src/modules/tote/ToteRenderer.ts

@ -5,7 +5,7 @@ import InstancePointManager from '@/core/manager/InstancePointManager.ts'
import type { Object3DLike } from '@/types/ModelTypes.ts' import type { Object3DLike } from '@/types/ModelTypes.ts'
import MODULE_3DS_File from '@/assets/Models/Tote.3ds?url' import MODULE_3DS_File from '@/assets/Models/Tote.3ds?url'
import MODULE_3DS_TEX from '@/assets/Models/ToteTex.png?url' import MODULE_3DS_TEX from '@/assets/Models/ToteTex.png?url'
import { load3DModule, loadByUrl, loadTexture } from '@/core/ModelUtils.ts' import { load3DModule, loadByUrl, loadTexture, processModel } from '@/core/ModelUtils.ts'
/** /**
* *
@ -26,6 +26,50 @@ export default class PalletRenderer extends BaseRenderer {
toteGeometry: THREE.BufferGeometry toteGeometry: THREE.BufferGeometry
toteMaterial: THREE.Material toteMaterial: THREE.Material
//
// processModel(mesh: THREE.Mesh) {
// const geometry = mesh.geometry.clone() as THREE.BufferGeometry
// geometry.rotateX(-Math.PI / 2)
//
// // 获取原始包围盒
// //@ts-ignore
// const box = new THREE.Box3().setFromBufferAttribute(geometry.attributes.position)
// const size = new THREE.Vector3()
// box.getSize(size)
//
// // 计算缩放因子:让整个包围盒变成 1x1x1 的立方体
// const scaleX = 1 / size.x
// const scaleY = 1 / size.y
// const scaleZ = 1 / size.z
//
// // 缩放几何体到 1x1x1 立方体(保持原点不变)
// geometry.scale(scaleX, scaleY, scaleZ)
//
// // 更新包围盒
// //@ts-ignore
// const scaledBox = new THREE.Box3().setFromBufferAttribute(geometry.attributes.position)
// const center = new THREE.Vector3()
// scaledBox.getCenter(center)
//
// // 平移:让中心在 (0, height/2, 0),底部贴地
// const translate = new THREE.Matrix4().makeTranslation(
// -center.x,
// -scaledBox.min.y, // 保证底部贴地
// -center.z
// )
// geometry.applyMatrix4(translate)
//
// // 可选:验证最终包围盒
// //@ts-ignore
// const finalBox = new THREE.Box3().setFromBufferAttribute(geometry.attributes.position)
// const finalSize = new THREE.Vector3()
// finalBox.getSize(finalSize)
// console.log('最终包围盒大小:', finalSize) // 应该是 (1, 1, 1)
// console.log('包围盒底部 Y 值:', finalBox.min.y) // 应该是 0
//
// return geometry
// }
init() { init() {
return Promise.all([ return Promise.all([
super.init(), super.init(),
@ -34,9 +78,15 @@ export default class PalletRenderer extends BaseRenderer {
]).then(([_, { data: queue3dsFile }, queueTexture]) => { ]).then(([_, { data: queue3dsFile }, queueTexture]) => {
const mesh = load3DModule(queue3dsFile, '.3ds').children[0] as THREE.Mesh const mesh = load3DModule(queue3dsFile, '.3ds').children[0] as THREE.Mesh
this.toteGeometry = mesh.geometry.rotateX(-Math.PI / 2) mesh.geometry.rotateX(-Math.PI / 2)
this.toteGeometry.scale(1, 1, 1) this.toteGeometry = processModel(mesh)
this.toteGeometry.center()
queueTexture.flipY = false
queueTexture.wrapS = THREE.RepeatWrapping
queueTexture.wrapT = THREE.RepeatWrapping
queueTexture.repeat.set(1, 1)
// this.toteMaterial = new THREE.MeshPhongMaterial({ color: 0x2b5d94 })
this.toteMaterial = mesh.material as THREE.Material this.toteMaterial = mesh.material as THREE.Material
//@ts-ignore //@ts-ignore
this.toteMaterial.map = queueTexture this.toteMaterial.map = queueTexture

Loading…
Cancel
Save