Browse Source

Merge remote-tracking branch 'origin/master'

master
lizw-2015 7 months ago
parent
commit
8d70e5af66
  1. 1
      src/components/Model3DView.vue
  2. 11
      src/core/Constract.ts
  3. 42
      src/core/ModelUtils.ts
  4. 9
      src/core/controls/SelectInspect.ts
  5. 6
      src/core/engine/Viewport.ts
  6. 4
      src/core/manager/WorldModel.ts
  7. 8
      src/editor/Model2DEditor.vue
  8. 40
      src/editor/widgets/property/PropertyView.vue
  9. 26
      src/example/example1.js
  10. 29
      src/modules/gstore/GstoreRenderer.ts
  11. 3
      src/modules/measure/MeasureRenderer.ts
  12. 91
      src/modules/rack/RackRenderer.ts
  13. 3
      src/modules/way/WayRenderer.ts

1
src/components/Model3DView.vue

@ -386,6 +386,7 @@ function createGroundStore() {
side: THREE.DoubleSide // :ml-citation{ref="5,8" data="citationList"}
});
const planeMesh = new THREE.Mesh(planeGeometry, material);
planeMesh.rotateX(Math.PI / 2)
scene.add(planeMesh);
}

11
src/core/Constract.ts

@ -1,4 +1,4 @@
export default Object.freeze({
const Constract = Object.freeze({
// 光标相关
CursorModeNormal: 'normal',
@ -17,7 +17,14 @@ export default Object.freeze({
CursorModeMeasure: 'measure',
CursorModeWay: 'way',
CursorModeGstore: 'gstore',
CursorModeRack: 'rack',
// 选择模式
CursorModeSelectByRec: 'selectByRec'
CursorModeSelectByRec: 'selectByRec',
HEIGHT_GSTORE: 0.03,
HEIGHT_MEASURE: 0.02,
HEIGHT_RACK: 0,
HEIGHT_WAY: 0.01
})
export default Constract

42
src/core/ModelUtils.ts

@ -6,6 +6,7 @@ import { computeBoundsTree, disposeBoundsTree } from 'three-mesh-bvh'
import { Vector2 } from 'three/src/math/Vector2'
import type Toolbox from '@/model/itemType/Toolbox.ts'
import EventBus from '@/runtime/EventBus.ts'
import Decimal from 'decimal.js'
/**
*
@ -140,7 +141,27 @@ export function deletePointByKeyboard() {
const entityId = viewport.state.selectedEntityId
if (!entityId) {
system.msg('没有选中任何点')
const multiSelectedEntityIds = viewport.state.multiSelectedEntityIds
if (!multiSelectedEntityIds && multiSelectedEntityIds.length === 0) {
system.msg('请选中要删除的实体', 'error')
return
}
const stateManager = viewport.stateManager
stateManager.beginStateUpdate()
const deleteItems = _.remove(stateManager.vdata.items, (item) => multiSelectedEntityIds.includes(item.id))
stateManager.endStateUpdate()
if (deleteItems.length === 0) {
system.msg('没有找到要删除的实体', 'error')
} else {
system.msg('删除了 ' + deleteItems.length + ' 个实体')
}
for (const deleteEntityId of multiSelectedEntityIds) {
EventBus.dispatch('entityDeleted', {
deleteEntityId: deleteEntityId
})
viewport.selectInspect.clearRedSelectionBoxes()
}
return
}
@ -161,6 +182,7 @@ export function deletePointByKeyboard() {
})
system.msg('删除 [' + entityId + ']')
viewport.selectInspect.clearSelectionBox()
}
export function escByKeyboard() {
@ -453,3 +475,21 @@ function loadObject3DFromJson(items: ItemJson[]): THREE.Object3D[] {
return result
}
/**
*
* @param collection
* @param iteratee
*/
export function decimalSumBy<T>(collection: ArrayLike<T> | null | undefined, iteratee?: ((value: T) => number)): number {
let sum = new Decimal(0)
_.forEach(collection, (t)=>{
if (typeof iteratee === 'function') {
sum = sum.add(new Decimal(iteratee(t)))
} else {
sum = sum.add(new Decimal(t))
}
})
return sum.toNumber()
}

9
src/core/controls/SelectInspect.ts

@ -167,7 +167,7 @@ export default class SelectInspect implements IControls {
* 线
*/
updateSelectionBox(selectedObject: THREE.Object3D) {
this.disposeSelectionBox()
this.clearSelectionBox()
if (!selectedObject) {
return
@ -214,11 +214,12 @@ export default class SelectInspect implements IControls {
puFn = undefined
// 销毁选择工具
this.disposeSelectionBox()
this.clearSelectionBox()
this.disposeRect()
this.clearRedSelectionBoxes()
}
disposeSelectionBox() {
clearSelectionBox() {
if (this.selectionBox) {
this.viewport.scene.remove(this.selectionBox)
this.selectionBox.geometry.dispose()
@ -311,7 +312,7 @@ export default class SelectInspect implements IControls {
if (Date.now() - clickTime < 200) {
// 如果是点击事件,触发选中逻辑
const objects: THREE.Object3D[] = this.viewport.entityManager.getObjectByCanvasMouse(event)
if (objects.length > 0) {
if (objects.length > 0 && objects[0]?.userData?.entityId) {
console.log('mouseClick', objects)
const object = objects[0]
const entityId = object.userData.entityId

6
src/core/engine/Viewport.ts

@ -37,10 +37,12 @@ export default class Viewport {
dragControl: any // EsDragControls
animationFrameId: any = null
scene: SceneHelp
selectInspect = new SelectInspect()
mouseMoveInspect = new MouseMoveInspect()
tools: IControls[] = [
new MouseMoveInspect(),
new SelectInspect()
markRaw(this.selectInspect),
markRaw(this.mouseMoveInspect)
]
// 状态管理器

4
src/core/manager/WorldModel.ts

@ -4,6 +4,7 @@ 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 StateManager from '@/core/manager/StateManager.ts'
export interface WorldModelState {
@ -64,7 +65,8 @@ export default class WorldModel {
return Promise.all([
Measure,
Way,
Gstore
Gstore,
Rack
]).then(() => {
console.log('世界模型初始化完成')

8
src/editor/Model2DEditor.vue

@ -53,6 +53,14 @@
:type="state?.cursorMode===Constract.CursorModeGstore?'primary':''"
@click="()=>state.cursorMode = Constract.CursorModeGstore"></el-button>
<el-button title="货架" :icon="renderIcon('antd BorderBottomOutlined')" link
:type="state?.cursorMode===Constract.CursorModeRack?'primary':''"
@click="()=>state.cursorMode = Constract.CursorModeRack"></el-button>
<el-button title="托盘" :icon="renderIcon('antd ProjectTwotone')" link
:type="state?.cursorMode===Constract.CursorModeRack?'primary':''"
@click="()=>state.cursorMode = Constract.CursorModeRack"></el-button>
</div>
<div class="section-toolbar-right">
<el-input v-model="searchKeyword" size="small" style="width: 110px; margin-right: 5px;"

40
src/editor/widgets/property/PropertyView.vue

@ -1,6 +1,7 @@
<template>
<div class="title">
属性面板
<template v-if="!!t">
属性 <el-tag type="primary">{{ t }}</el-tag>
<el-input v-model="searchKeyword" size="small" style="width: 240px" placeholder="Search">
<template #prefix>
<component :is="renderIcon('element Search')"></component>
@ -9,15 +10,17 @@
<span class="close" @click="closeMe()">
<component :is="renderIcon('element Close')" />
</span>
</template>
</div>
<div class="calc-right-panel">
<el-form
<el-empty v-if="!t" description="未选中">
</el-empty>
<el-form v-else
label-position="right"
label-width="60"
class="property-panel-form"
size="default"
@submit.native.prevent
>
@submit.native.prevent>
<template v-for="(itemMeta, idx) in selectedObjectMeta">
<el-divider v-if="itemMeta.editor === '-'" />
@ -49,7 +52,7 @@
:viewport="viewport"
/>
<template v-else> 未知编辑器: {{ itemMeta.editor }} </template>
<template v-else> 未知编辑器: {{ itemMeta.editor }}</template>
</template>
</el-form>
</div>
@ -75,13 +78,18 @@ export default {
},
mixins: [IWidgets],
data() {
return {
itemTypeMeta: null,
searchKeyword: ''
}
},
computed: {
t() {
return this.selectedItem ? ('(' + this.selectedItem.t + ')') : ''
},
selectedItem() {
return this.state?.selectedItem
},
selectedObject() {
return this.state?.selectedObject
},
@ -91,24 +99,24 @@ export default {
},
methods: {
selectedObjectChanged(state) {
const data = state.selectedItem;
console.log("selectedObjectChanged data", data)
if(data) {
const data = state.selectedItem
console.log('selectedObjectChanged data', data)
if (data) {
this.viewport.stateManager.beginStateUpdate()
const item = _.find(this.viewport.stateManager.vdata.items, item => item.id === data.id)
// item.tf[0][0] = item.tf[0][0] / 2;
console.log("selectedObjectChanged item", item)
console.log('selectedObjectChanged item', item)
// _.extend(item, data)
this.viewport.stateManager.endStateUpdate()
}
},
}
},
mounted() {
EventBus.on("selectedObjectChanged", this.selectedObjectChanged);
EventBus.on('selectedObjectChanged', this.selectedObjectChanged)
},
unmounted() {
EventBus.off("selectedObjectChanged", this.selectedObjectChanged);
},
EventBus.off('selectedObjectChanged', this.selectedObjectChanged)
}
}
</script>
<style lang="less">
@ -116,13 +124,16 @@ export default {
margin: 0;
font-size: 14px;
color: #606266;
.el-form-item--default {
margin: 5px 3px 0 0;
.el-form-item__label {
height: 20px;
line-height: 22px;
}
}
.gui-toolbar {
color: #333;
background: #ffffff;
@ -168,6 +179,7 @@ export default {
}
}
}
.el-divider {
margin: 5px 0;
}

26
src/example/example1.js

@ -77,6 +77,32 @@ export default {
// }
// }
{
id: 'rack1',
t: 'rack',
v: true,
tf: [[-1, 0.1, 3.5], [0, 0, 0], [1.5, 0.25, 0.1]],
dt: {
rackDepth: 1, // 货架深度
rackWidth: 8,
rackHeight: 4.2,
levelCount: 3, // 总层数
bayCount: 5, // 总列数
hideFloor: false, // 隐藏底板
extendColumns: true, // 扩展挡板
columnSpacing: 1, // 支脚跨越
bays: [ // 每列的配置
{
bayWidth: 1.6, // 列的宽度
levelHeight: [ 1.4, 1.4, 1.4 ] // 每层的高度
},
{bayWidth: 1.6, levelHeight: [ 1.4, 1.4, 1.4 ]},
{bayWidth: 1.6, levelHeight: [ 1.4, 1.4, 1.4 ]},
{bayWidth: 1.6, levelHeight: [ 1.4, 1.4, 1.4 ]},
{bayWidth: 1.6, levelHeight: [ 1.4, 1.4, 1.4 ]},
]
}
},
{
id: 'P1',
t: 'measure',
v: true,

29
src/modules/gstore/GstoreRenderer.ts

@ -3,6 +3,7 @@ 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'
/**
*
@ -15,7 +16,7 @@ export default class GstoreRenderer extends BaseRenderer {
/**
* ,
*/
readonly defulePositionY: number = 0.5 // 默认点的高度, 0.01, 防止和地面重合
readonly defulePositionY: number = Constract.HEIGHT_GSTORE
readonly defaultScale: THREE.Vector3 = new THREE.Vector3(1.5, 1.2, 0.1)
readonly defaultRotation: THREE.Vector3 = new THREE.Vector3(0, 0, 0)
readonly defaultLineWidth: number = 0.05
@ -56,7 +57,7 @@ export default class GstoreRenderer extends BaseRenderer {
group.name = GstoreRenderer.POINT_NAME
// 绘制背景矩形框
const planeGeometry = new THREE.PlaneGeometry(item.dt.storeWidth, item.dt.storeDepth)
const planeGeometry = new THREE.PlaneGeometry(1, 1);
planeGeometry.rotateX(-Math.PI / 2)
const planeMaterial = new THREE.MeshBasicMaterial({
color: 'white',
@ -64,8 +65,8 @@ export default class GstoreRenderer extends BaseRenderer {
opacity: 0.2, // 50%透明度
depthWrite: false, // 防止深度冲突
side: THREE.DoubleSide // 双面渲染:ml-citation{ref="5,8" data="citationList"}
})
const planeMesh = new THREE.Mesh(planeGeometry, planeMaterial)
});
const planeMesh = new THREE.Mesh(planeGeometry, planeMaterial);
group.add(planeMesh)
if (!item.dt.storeWidth || !item.dt.storeDepth) {
@ -77,22 +78,22 @@ export default class GstoreRenderer extends BaseRenderer {
const lineYLen = item.dt.storeDepth - this.defaultLineWidth
const lineGeometry = new LineGeometry().setPositions([
-(lineXLen / 2), -(lineYLen / 2), 0,
lineXLen / 2, -(lineYLen / 2), 0,
lineXLen / 2, lineYLen / 2, 0,
-(lineXLen / 2), lineYLen / 2, 0,
-(lineXLen / 2), -(lineYLen / 2), 0
])
-(lineXLen/2),-(lineYLen/2),0,
lineXLen/2,-(lineYLen/2),0,
lineXLen/2,lineYLen/2,0,
-(lineXLen/2),lineYLen/2,0,
-(lineXLen/2),-(lineYLen/2),0
]);
lineGeometry.rotateX(-Math.PI / 2)
const lineMaterial = new LineMaterial({
color: 0x00ff00,
color: '#038217',
linewidth: 0.05,
worldUnits: true,
resolution: new THREE.Vector2(window.innerWidth, window.innerHeight),
side: THREE.DoubleSide
})
});
//
const line = new Line2(lineGeometry, lineMaterial)
const line = new Line2(lineGeometry, lineMaterial);
group.add(line as THREE.Object3D)
return [group]
@ -100,6 +101,6 @@ export default class GstoreRenderer extends BaseRenderer {
dispose() {
super.dispose()
this.pointMaterial?.dispose()
this.pointMaterial.dispose()
}
}

3
src/modules/measure/MeasureRenderer.ts

@ -8,6 +8,7 @@ import { numberToString } from '@/utils/webutils.ts'
import { CSS2DObject } from 'three/examples/jsm/renderers/CSS2DRenderer'
import { Text } from 'troika-three-text'
import SimSunTTF from '@/assets/fonts/simsunb.ttf'
import Constract from '@/core/Constract.ts'
/**
*
@ -28,7 +29,7 @@ export default class MeasureRenderer extends BaseRenderer {
pointMaterial: THREE.Material
lineMaterial: LineMaterial
readonly defulePositionY = 0.01
readonly defulePositionY = Constract.HEIGHT_MEASURE
readonly defaultScale: THREE.Vector3 = new THREE.Vector3(0.1, 0.1, 0.1)
readonly defaultRotation: THREE.Vector3 = new THREE.Vector3(90, 0, 0)

91
src/modules/rack/RackRenderer.ts

@ -3,20 +3,22 @@ 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'
/**
*
*
*/
export default class RackRenderer extends BaseRenderer {
static POINT_NAME = 'ground_store'
static POINT_NAME = 'rack'
pointMaterial: THREE.Material
/**
* ,
*/
readonly defulePositionY: number = 0.5 // 默认点的高度, 0.01, 防止和地面重合
readonly defaultScale: THREE.Vector3 = new THREE.Vector3(1.5, 1.2, 0.1)
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
@ -32,7 +34,8 @@ export default class RackRenderer extends BaseRenderer {
const point = objects[0]
point.position.y = this.defulePositionY
point.scale.set(item.dt.storeWidth, this.defaultScale.y, item.dt.storeDepth)
//point.scale.set(_.sumBy(item.dt.bays, b=>b.bayWidth), this.defaultScale.y, item.dt.rackDepth)
point.rotation.set(
THREE.MathUtils.degToRad(this.defaultRotation.x),
THREE.MathUtils.degToRad(this.defaultRotation.y),
@ -49,57 +52,95 @@ export default class RackRenderer extends BaseRenderer {
throw new Error('not allow store line.')
}
createPointBasic(item: ItemJson, option?: RendererCudOption): THREE.Object3D[] {
createPoint(item: ItemJson, option?: RendererCudOption): THREE.Object3D[] {
// 创建平面几何体
const group = new THREE.Group()
group.name = RackRenderer.POINT_NAME
const rackWidth = decimalSumBy(item.dt.bays, b=>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(item.dt.storeWidth, item.dt.storeDepth);
planeGeometry.rotateX(-Math.PI / 2)
const planeGeometry = new THREE.PlaneGeometry(rackWidth, item.dt.rackDepth);
planeGeometry.rotateX(Math.PI / 2)
const planeMaterial = new THREE.MeshBasicMaterial({
color: 'white',
color: '#9a9090',
transparent: true, // 启用透明
opacity: 0.2, // 50%透明度
opacity: 0.5, // 50%透明度
depthWrite: false, // 防止深度冲突
side: THREE.DoubleSide // 双面渲染:ml-citation{ref="5,8" data="citationList"}
});
const planeMesh = new THREE.Mesh(planeGeometry, planeMaterial);
})
const planeMesh = new THREE.Mesh(planeGeometry, planeMaterial)
group.add(planeMesh)
if (!item.dt.storeWidth || !item.dt.storeDepth) {
if (!item.dt.bays || !item.dt.rackDepth) {
return [group]
}
// 绘制边框
const lineXLen = item.dt.storeWidth - this.defaultLineWidth
const lineYLen = item.dt.storeDepth - this.defaultLineWidth
const lineXLen = rackWidth - this.defaultLineWidth
const lineYLen = item.dt.rackDepth - this.defaultLineWidth
const lineGeometry = new LineGeometry().setPositions([
-(lineXLen/2),-(lineYLen/2),0,
lineXLen/2,-(lineYLen/2),0,
lineXLen/2,lineYLen/2,0,
-(lineXLen/2),lineYLen/2,0,
-(lineXLen/2),-(lineYLen/2),0
]);
lineGeometry.rotateX(-Math.PI / 2)
-(lineXLen/2),0,-(lineYLen/2),
lineXLen/2,0,-(lineYLen/2),
lineXLen/2,0,lineYLen/2,
-(lineXLen/2),0,lineYLen/2,
-(lineXLen/2),0,-(lineYLen/2)
])
const lineMaterial = new LineMaterial({
color: 0x00ff00,
color: '#0d89a5',
linewidth: 0.05,
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)
return [group]
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)
}
// 设置位置
group.position.set(item.tf[0][0], item.tf[0][1], item.tf[0][2])
item.dt.rackWidth = rackWidth
item.dt.rackHeight = rackHeight
const points = [group]
this.fillObjectUserDataFromItem(item, ...points)
this.afterCreateOrUpdatePoint(item, option, points)
this.tempViewport.entityManager.appendObject(item.id, points)
this.appendToScene(...points)
return points
}
dispose() {
super.dispose()
this.pointMaterial.dispose()
}
createPointBasic(item: ItemJson, option?: RendererCudOption): Object3D[] {
return [];
}
}

3
src/modules/way/WayRenderer.ts

@ -6,6 +6,7 @@ import SimSunTTF from '@/assets/fonts/simsunb.ttf'
import { getLineId } from '@/core/ModelUtils.ts'
import { CSS2DObject } from 'three/examples/jsm/renderers/CSS2DRenderer'
import { numberToString } from '@/utils/webutils.ts'
import Constract from '@/core/Constract.ts'
/**
*
@ -28,7 +29,7 @@ export default class WayRenderer extends BaseRenderer {
/**
* ,
*/
readonly defulePositionY: number = 0.8 // 默认点的高度, 0.01, 防止和地面重合
readonly defulePositionY: number = Constract.HEIGHT_WAY
readonly defaultScale: THREE.Vector3 = new THREE.Vector3(0.25, 0.25, 0.1)
readonly defaultRotation: THREE.Vector3 = new THREE.Vector3(90, 0, 0)

Loading…
Cancel
Save