|
|
@ -4,10 +4,6 @@ |
|
|
<span class="section-toolbar-line" style="margin-left: 85px;"></span> |
|
|
<span class="section-toolbar-line" style="margin-left: 85px;"></span> |
|
|
<el-button :icon="renderIcon('antd ClusterOutlined')" link></el-button> |
|
|
<el-button :icon="renderIcon('antd ClusterOutlined')" link></el-button> |
|
|
<span class="section-toolbar-line"></span> |
|
|
<span class="section-toolbar-line"></span> |
|
|
<el-cascader placeholder="选择楼层" size="small" v-model="currentLevel" |
|
|
|
|
|
:options="calcCatalog" filterable :show-all-levels="false" clearable |
|
|
|
|
|
:props="{emitPath:false}" /> |
|
|
|
|
|
<span class="section-toolbar-line"></span> |
|
|
|
|
|
<el-button-group> |
|
|
<el-button-group> |
|
|
<el-button :icon="renderIcon('antd CameraFilled')" link |
|
|
<el-button :icon="renderIcon('antd CameraFilled')" link |
|
|
:type="state?.view3DMode===Constract.Mode2D?'primary':''" |
|
|
:type="state?.view3DMode===Constract.Mode2D?'primary':''" |
|
|
@ -22,7 +18,7 @@ |
|
|
</el-button> |
|
|
</el-button> |
|
|
<el-upload :on-change="addCADDxf" |
|
|
<el-upload :on-change="addCADDxf" |
|
|
:show-file-list="false" accept=".dxf" action="" :auto-upload="false"> |
|
|
:show-file-list="false" accept=".dxf" action="" :auto-upload="false"> |
|
|
<el-button :icon="renderIcon('element Files')" link > |
|
|
<el-button :icon="renderIcon('element Files')" link> |
|
|
添加CAD图纸 |
|
|
添加CAD图纸 |
|
|
</el-button> |
|
|
</el-button> |
|
|
</el-upload> |
|
|
</el-upload> |
|
|
@ -30,9 +26,9 @@ |
|
|
</el-button-group> |
|
|
</el-button-group> |
|
|
</div> |
|
|
</div> |
|
|
<div class="section-content"> |
|
|
<div class="section-content"> |
|
|
<div v-if="currentStateManagerId" :key="currentStateManagerId || getRandom()" |
|
|
<div v-if="currentStateManagerId" :key="currentStateManagerVersion" |
|
|
:StateManagerId="currentStateManagerId" |
|
|
class="canvas-container" ref="canvasContainer" tabindex="1" |
|
|
class="canvas-container" ref="canvasContainer" tabindex="1" /> |
|
|
/> |
|
|
</div> |
|
|
</div> |
|
|
<div class="section-bottom-toolbar section-toolbar" v-if="!!state"> |
|
|
<div class="section-bottom-toolbar section-toolbar" v-if="!!state"> |
|
|
<div class="section-toolbar-left"> |
|
|
<div class="section-toolbar-left"> |
|
|
@ -109,9 +105,10 @@ import Constract from '@/core/Constract' |
|
|
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' |
|
|
import lodash from "lodash"; |
|
|
import lodash from 'lodash' |
|
|
import { DXFViewer } from 'three-dxf-viewer'; |
|
|
import { DXFViewer } from 'three-dxf-viewer' |
|
|
import cadFont from "@/assets/fonts/helvetiker_regular.typeface.json?url" |
|
|
import cadFont from '@/assets/fonts/helvetiker_regular.typeface.json?url' |
|
|
|
|
|
import StateManager from '@/core/manager/StateManager.js' |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
export default defineComponent({ |
|
|
export default defineComponent({ |
|
|
@ -124,17 +121,13 @@ export default defineComponent({ |
|
|
scene: null, |
|
|
scene: null, |
|
|
viewport: null, |
|
|
viewport: null, |
|
|
currentStateManagerId: null, |
|
|
currentStateManagerId: null, |
|
|
|
|
|
currentStateManagerVersion: 0, |
|
|
searchKeyword: '' |
|
|
searchKeyword: '' |
|
|
} |
|
|
} |
|
|
}, |
|
|
}, |
|
|
mounted() { |
|
|
mounted() { |
|
|
if (worldModel.state.isDraft) { |
|
|
this.$nextTick(() => { |
|
|
// 如果是草稿状态, 则不加载视口 |
|
|
this.initByFloor(worldModel.currentStateManager) |
|
|
this.initByFloor() |
|
|
|
|
|
} |
|
|
|
|
|
EventBus.on('catalogChanged', (floor) => { |
|
|
|
|
|
// 当楼层加载完成后, 初始化视口 |
|
|
|
|
|
this.initByFloor() |
|
|
|
|
|
}) |
|
|
}) |
|
|
}, |
|
|
}, |
|
|
beforeUnmount() { |
|
|
beforeUnmount() { |
|
|
@ -142,20 +135,18 @@ export default defineComponent({ |
|
|
}, |
|
|
}, |
|
|
methods: { |
|
|
methods: { |
|
|
renderIcon, |
|
|
renderIcon, |
|
|
getRandom() { |
|
|
|
|
|
return Math.random().toString(36).substring(2, 15) |
|
|
|
|
|
}, |
|
|
|
|
|
destroyScene() { |
|
|
destroyScene() { |
|
|
if (this.viewport) { |
|
|
|
|
|
this.viewport.dispose() |
|
|
|
|
|
this.viewport = null |
|
|
|
|
|
delete window['viewport'] |
|
|
|
|
|
} |
|
|
|
|
|
if (this.scene) { |
|
|
if (this.scene) { |
|
|
this.scene.dispose() |
|
|
this.scene.dispose() |
|
|
this.scene = null |
|
|
this.scene = null |
|
|
delete window['scene'] |
|
|
delete window['scene'] |
|
|
} |
|
|
} |
|
|
|
|
|
if (this.viewport) { |
|
|
|
|
|
this.viewport.dispose() |
|
|
|
|
|
this.viewport = null |
|
|
|
|
|
} |
|
|
|
|
|
this.currentStateManagerId = null |
|
|
|
|
|
this.currentStateManagerVersion++ |
|
|
this.isReady = false |
|
|
this.isReady = false |
|
|
}, |
|
|
}, |
|
|
toFixed(num) { |
|
|
toFixed(num) { |
|
|
@ -167,28 +158,21 @@ export default defineComponent({ |
|
|
} |
|
|
} |
|
|
return parseFloat(num).toFixed(2) |
|
|
return parseFloat(num).toFixed(2) |
|
|
}, |
|
|
}, |
|
|
initByFloor() { |
|
|
initByFloor(stateManager) { |
|
|
this.destroyScene() |
|
|
this.destroyScene() |
|
|
|
|
|
|
|
|
if (!this.$el || this.$.isUnmounted) { |
|
|
if (!this.$el || this.$.isUnmounted) { |
|
|
// 检查组件是否已卸载, 幻影加载问题 |
|
|
// 检查组件是否已卸载, 幻影加载问题 |
|
|
|
|
|
console.warn('Model2DEditor component is unmounted, skipping initialization.') |
|
|
return |
|
|
return |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
delete window['editor'] |
|
|
delete window['editor'] |
|
|
delete window['viewport'] |
|
|
|
|
|
delete window['scene'] |
|
|
const id = this.worldModelState.stateManagerId |
|
|
delete window['stateManager'] |
|
|
|
|
|
delete window['entityManager'] |
|
|
|
|
|
delete window['renderer'] |
|
|
|
|
|
delete window['camera'] |
|
|
|
|
|
delete window['renderer'] |
|
|
|
|
|
delete window['controls'] |
|
|
|
|
|
|
|
|
|
|
|
const id = worldModel.state.stateManagerId |
|
|
|
|
|
this.currentStateManagerId = id |
|
|
this.currentStateManagerId = id |
|
|
|
|
|
this.currentStateManagerVersion++ |
|
|
|
|
|
|
|
|
if (!worldModel.state.catalogCode || !worldModel.state.isOpened || !id) { |
|
|
if (!this.worldModelState.catalogCode || !this.worldModelState.isOpened || !id) { |
|
|
// 放弃加载 |
|
|
// 放弃加载 |
|
|
setQueryParam('store', '') |
|
|
setQueryParam('store', '') |
|
|
return |
|
|
return |
|
|
@ -212,7 +196,7 @@ export default defineComponent({ |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
const sceneHelp = new SceneHelp(worldModel, worldModel.state.catalogCode) |
|
|
const sceneHelp = new SceneHelp(worldModel, worldModel.state.catalogCode) |
|
|
const viewport = new Viewport(sceneHelp, viewerDom) |
|
|
const viewport = new Viewport(sceneHelp, viewerDom, stateManager) |
|
|
|
|
|
|
|
|
this.scene = markRaw(sceneHelp) |
|
|
this.scene = markRaw(sceneHelp) |
|
|
this.viewport = markRaw(viewport) |
|
|
this.viewport = markRaw(viewport) |
|
|
@ -222,15 +206,7 @@ export default defineComponent({ |
|
|
setQueryParam('store', id) |
|
|
setQueryParam('store', id) |
|
|
// window.history.replaceState({}, '', window.location.href + '?store=' + id) |
|
|
// window.history.replaceState({}, '', window.location.href + '?store=' + id) |
|
|
|
|
|
|
|
|
window['viewport'] = viewport |
|
|
|
|
|
window['THREE'] = THREE |
|
|
window['THREE'] = THREE |
|
|
window['scene'] = sceneHelp.scene |
|
|
|
|
|
window['stateManager'] = viewport.stateManager |
|
|
|
|
|
window['entityManager'] = viewport.entityManager |
|
|
|
|
|
window['renderer'] = viewport.renderer |
|
|
|
|
|
window['camera'] = viewport.camera |
|
|
|
|
|
window['renderer'] = viewport.renderer |
|
|
|
|
|
window['controls'] = viewport.controls |
|
|
|
|
|
|
|
|
|
|
|
//@ts-ignore |
|
|
//@ts-ignore |
|
|
viewerDom.focus() |
|
|
viewerDom.focus() |
|
|
@ -249,6 +225,7 @@ export default defineComponent({ |
|
|
} else { |
|
|
} else { |
|
|
console.error('Canvas container not found after retries') |
|
|
console.error('Canvas container not found after retries') |
|
|
this.currentStateManagerId = '' |
|
|
this.currentStateManagerId = '' |
|
|
|
|
|
this.currentStateManagerVersion++ |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
@ -258,18 +235,18 @@ export default defineComponent({ |
|
|
|
|
|
|
|
|
}, |
|
|
}, |
|
|
showBulkCopy() { |
|
|
showBulkCopy() { |
|
|
const viewport = this.viewport; |
|
|
const viewport = this.viewport |
|
|
const selectedItem = viewport?.state?.selectedItem; |
|
|
const selectedItem = viewport?.state?.selectedItem |
|
|
if(!viewport || !selectedItem) return; |
|
|
if (!viewport || !selectedItem) return |
|
|
const config = { |
|
|
const config = { |
|
|
numberOfRows: 1, |
|
|
numberOfRows: 1, |
|
|
numberOfColumns: 1, |
|
|
numberOfColumns: 1, |
|
|
rowSpace: 0, |
|
|
rowSpace: 0, |
|
|
columnSpacing: 0, |
|
|
columnSpacing: 0, |
|
|
doubleRow: false, |
|
|
doubleRow: false |
|
|
}; |
|
|
} |
|
|
system.showDialog(createVNode(BulkCopy, { |
|
|
system.showDialog(createVNode(BulkCopy, { |
|
|
config, |
|
|
config |
|
|
}), { |
|
|
}), { |
|
|
title: '批量复制', |
|
|
title: '批量复制', |
|
|
width: 520, |
|
|
width: 520, |
|
|
@ -277,83 +254,64 @@ export default defineComponent({ |
|
|
showClose: true, |
|
|
showClose: true, |
|
|
showMax: true, |
|
|
showMax: true, |
|
|
showCancelButton: false, |
|
|
showCancelButton: false, |
|
|
showOkButton: true, |
|
|
showOkButton: true |
|
|
}).then(() => { |
|
|
}).then(() => { |
|
|
if(!config.numberOfRows || !config.numberOfColumns) return; |
|
|
if (!config.numberOfRows || !config.numberOfColumns) return |
|
|
viewport.stateManager.update(({ getEntity, addEntity }) => { |
|
|
viewport.stateManager.update(({ getEntity, addEntity }) => { |
|
|
const xAxle = selectedItem.tf[0][0]; |
|
|
const xAxle = selectedItem.tf[0][0] |
|
|
const zAxle = selectedItem.tf[0][2]; |
|
|
const zAxle = selectedItem.tf[0][2] |
|
|
const xSize = selectedItem.tf[2][0]; |
|
|
const xSize = selectedItem.tf[2][0] |
|
|
const zSize = selectedItem.tf[2][2]; |
|
|
const zSize = selectedItem.tf[2][2] |
|
|
console.log("item", JSON.stringify(selectedItem.tf)); |
|
|
console.log('item', JSON.stringify(selectedItem.tf)) |
|
|
for (let rCount = 0; rCount < config.numberOfRows; rCount++) { |
|
|
for (let rCount = 0; rCount < config.numberOfRows; rCount++) { |
|
|
for (let cCount = 0; cCount < config.numberOfColumns; cCount++) { |
|
|
for (let cCount = 0; cCount < config.numberOfColumns; cCount++) { |
|
|
if(rCount===0 && cCount===0) continue; |
|
|
if (rCount === 0 && cCount === 0) continue |
|
|
const item = lodash.cloneDeep(selectedItem); |
|
|
const item = lodash.cloneDeep(selectedItem) |
|
|
item.id = system.createUUID(); |
|
|
item.id = system.createUUID() |
|
|
item.tf[0][0] = xAxle + cCount * (xSize + config.columnSpacing); |
|
|
item.tf[0][0] = xAxle + cCount * (xSize + config.columnSpacing) |
|
|
item.tf[0][2] = zAxle + rCount * (zSize + config.rowSpace); |
|
|
item.tf[0][2] = zAxle + rCount * (zSize + config.rowSpace) |
|
|
addEntity(item); |
|
|
addEntity(item) |
|
|
console.log("item", JSON.stringify(item.tf)); |
|
|
console.log('item', JSON.stringify(item.tf)) |
|
|
} |
|
|
|
|
|
} |
|
|
} |
|
|
}); |
|
|
} |
|
|
console.log("config", config, selectedItem); |
|
|
}) |
|
|
}).finally(); |
|
|
console.log('config', config, selectedItem) |
|
|
|
|
|
}).finally() |
|
|
}, |
|
|
}, |
|
|
|
|
|
|
|
|
async addCADDxf(file) { |
|
|
async addCADDxf(file) { |
|
|
|
|
|
|
|
|
// 创建一个边长为 1 的红色立方体 |
|
|
// 创建一个边长为 1 的红色立方体 |
|
|
const geometry = new THREE.BoxGeometry(1, 1, 1); |
|
|
const geometry = new THREE.BoxGeometry(1, 1, 1) |
|
|
const material = new THREE.MeshBasicMaterial({ color: 0xff0000 }); |
|
|
const material = new THREE.MeshBasicMaterial({ color: 0xff0000 }) |
|
|
const cube = new THREE.Mesh(geometry, material); |
|
|
const cube = new THREE.Mesh(geometry, material) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
console.log('file', file) |
|
|
console.log('file', file) |
|
|
if (!file) return |
|
|
if (!file) return |
|
|
|
|
|
|
|
|
file = file.raw |
|
|
file = file.raw |
|
|
const viewer = new DXFViewer(); |
|
|
const viewer = new DXFViewer() |
|
|
let dxf = await viewer.getFromFile(file, cadFont); |
|
|
let dxf = await viewer.getFromFile(file, cadFont) |
|
|
dxf.scale.set(0.001, 0.001, 0.001) |
|
|
dxf.scale.set(0.001, 0.001, 0.001) |
|
|
dxf.rotation.x = -Math.PI / 2 |
|
|
dxf.rotation.x = -Math.PI / 2 |
|
|
// Add the geometry to the scene |
|
|
// Add the geometry to the scene |
|
|
const group = new THREE.Group(); |
|
|
const group = new THREE.Group() |
|
|
group.add(dxf); |
|
|
group.add(dxf) |
|
|
this.scene.add(group); |
|
|
this.scene.add(group) |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
}, |
|
|
}, |
|
|
computed: { |
|
|
computed: { |
|
|
|
|
|
worldModelState() { |
|
|
|
|
|
return worldModel.state |
|
|
|
|
|
}, |
|
|
state() { |
|
|
state() { |
|
|
return this.viewport?.state |
|
|
return this.viewport?.state |
|
|
}, |
|
|
}, |
|
|
currentLevel: { |
|
|
|
|
|
get() { |
|
|
|
|
|
return worldModel.state.catalogCode |
|
|
|
|
|
}, |
|
|
|
|
|
set(newVal) { |
|
|
|
|
|
worldModel.state.catalogCode = newVal |
|
|
|
|
|
} |
|
|
|
|
|
}, |
|
|
|
|
|
calcCatalog() { |
|
|
|
|
|
if (!worldModel.state.catalog || !worldModel.state.isOpened) { |
|
|
|
|
|
return [] |
|
|
|
|
|
} |
|
|
|
|
|
return worldModel.state.catalog.map(group => ({ |
|
|
|
|
|
value: group.label, |
|
|
|
|
|
label: group.label, |
|
|
|
|
|
children: group.items.map(item => ({ |
|
|
|
|
|
value: item.catalogCode, |
|
|
|
|
|
label: item.label |
|
|
|
|
|
})) |
|
|
|
|
|
})) |
|
|
|
|
|
}, |
|
|
|
|
|
selectedObject() { |
|
|
selectedObject() { |
|
|
return this.state?.selectedObject; |
|
|
return this.state?.selectedObject |
|
|
}, |
|
|
} |
|
|
} |
|
|
} |
|
|
}) |
|
|
}) |
|
|
</script> |
|
|
</script> |
|
|
|