From 71ede82ce3fbd1d354120440c450f8e2d9e5225f Mon Sep 17 00:00:00 2001 From: luoyifan Date: Sun, 8 Jun 2025 19:09:06 +0800 Subject: [PATCH] =?UTF-8?q?=E6=80=A7=E8=83=BD=E6=B5=8B=E8=AF=95=E6=B8=B2?= =?UTF-8?q?=E6=9F=93?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/ThreePerfView.vue | 87 +++++++++++--- src/example/ExampleUtil.js | 38 +++--- src/modules/measure/MeasureRenderer.ts | 208 ++++++++++++++++----------------- 3 files changed, 192 insertions(+), 141 deletions(-) diff --git a/src/components/ThreePerfView.vue b/src/components/ThreePerfView.vue index a9fbba9..83054c1 100644 --- a/src/components/ThreePerfView.vue +++ b/src/components/ThreePerfView.vue @@ -21,6 +21,9 @@ import Stats from 'three/examples/jsm/libs/stats.module' import { LineGeometry } from 'three/examples/jsm/lines/LineGeometry' import { LineMaterial } from 'three/examples/jsm/lines/LineMaterial' import { Line2 } from 'three/examples/jsm/lines/Line2' +import MeasureRenderer from '@/modules/measure/MeasureRenderer.ts' +import { LineSegmentsGeometry } from 'three/examples/jsm/lines/LineSegmentsGeometry' +import { LineSegments2 } from 'three/examples/jsm/lines/LineSegments2' const canvasContainer = ref(null) let resizeObserver: ResizeObserver | null = null @@ -42,17 +45,22 @@ const pointMaterial = new THREE.SpriteMaterial({ opacity: 1, sizeAttenuation: true }) +// const lineMaterial = new LineMaterial({ +// color: 0xFF8C00, +// linewidth: 5, +// vertexColors: false, +// dashed: false +// }) const lineMaterial = new LineMaterial({ color: 0xFF8C00, - linewidth: 5, - vertexColors: false, - dashed: false -}) + linewidth: 5 +}); function test1() { const xcount = 100 const zcount = 100 - const dist = 1.2 + const dist = 1.25 + const spacing = dist const y = 0.1 const points = [] @@ -70,32 +78,75 @@ function test1() { } } - // 绘制线段 - const lines = [] - -// 绘制线段(每两个点一组) +// // 绘制线段 +// const lines = [] +// +// // 绘制线段(每两个点一组) +// for (let z = 0; z < zcount; z++) { +// for (let x = 0; x < xcount - 1; x++) { +// const i = z * xcount + x +// drawLine(points[i], points[i + 1]) +// } +// } +// +// for (let z = 0; z < zcount - 1; z++) { +// for (let x = 0; x < xcount; x++) { +// const i = z * xcount + x +// const belowIndex = (z + 1) * xcount + x +// drawLine(points[i], points[belowIndex]) +// } +// } + const positions = []; + + // 横向连接(右) for (let z = 0; z < zcount; z++) { for (let x = 0; x < xcount - 1; x++) { - const i = z * xcount + x - drawLine(points[i], points[i + 1]) + const x1 = x * spacing; + const z1 = z * spacing; + const x2 = (x + 1) * spacing; + const z2 = z * spacing; + positions.push(x1, y, z1, x2, y, z2); } } + // 纵向连接(下) for (let z = 0; z < zcount - 1; z++) { for (let x = 0; x < xcount; x++) { - const i = z * xcount + x - const belowIndex = (z + 1) * xcount + x - drawLine(points[i], points[belowIndex]) + const x1 = x * spacing; + const z1 = z * spacing; + const x2 = x * spacing; + const z2 = (z + 1) * spacing; + positions.push(x1, y, z1, x2, y, z2); } } + + const geometry = new LineSegmentsGeometry(); + geometry.setPositions(positions); // [x1,y1,z1, x2,y2,z2, ...] + + const material = new LineMaterial({ + color: 0xFF8C00, + linewidth: 5, + vertexColors: false + }); + + const lineSegments = new LineSegments2(geometry, material); + lineSegments.computeLineDistances(); // 必须调用一次 + lineSegments.name = 'grid-lines'; + scene.add(lineSegments); } function drawLine(p1: THREE.Vector3, p2: THREE.Vector3) { - const geometry = new LineGeometry() - geometry.setPositions([p1.x, p1.y, p1.z, p2.x, p2.y, p2.z]) + const geometry = new LineGeometry(); + geometry.setPositions([p1.x, p1.y, p1.z, p2.x, p2.y, p2.z]); + + // const material = new LineMaterial({ + // color: 0xFF8C00, + // linewidth: 5 + // }); + + const line = new Line2(geometry, lineMaterial); + line.computeLineDistances(); - const line = new Line2(geometry, lineMaterial) - line.computeLineDistances() // 可选:用于渐变等效果 scene.add(line) } diff --git a/src/example/ExampleUtil.js b/src/example/ExampleUtil.js index 15b9940..9ed98c7 100644 --- a/src/example/ExampleUtil.js +++ b/src/example/ExampleUtil.js @@ -18,25 +18,25 @@ export function buildAgvPerformanceData(rows, cols) { data.set(node.id, node) // 与前一个点进行连线 - // if (row > 0 && col > 0) { - // const preXNode = data.get('wp_' + (row - 1) + '_' + (col)) - // node.dt.center.push(preXNode.id) - // preXNode.dt.center.push(node.id) - // - // const preYNode = data.get('wp_' + (row) + '_' + (col - 1)) - // node.dt.center.push(preYNode.id) - // preYNode.dt.center.push(node.id) - // - // } else if (row > 0) { - // const preXNode = data.get('wp_' + (row - 1) + '_' + (col)) - // node.dt.center.push(preXNode.id) - // preXNode.dt.center.push(node.id) - // - // } else if (col > 0) { - // const preYNode = data.get('wp_' + (row) + '_' + (col - 1)) - // node.dt.center.push(preYNode.id) - // preYNode.dt.center.push(node.id) - // } + if (row > 0 && col > 0) { + const preXNode = data.get('wp_' + (row - 1) + '_' + (col)) + node.dt.center.push(preXNode.id) + preXNode.dt.center.push(node.id) + + const preYNode = data.get('wp_' + (row) + '_' + (col - 1)) + node.dt.center.push(preYNode.id) + preYNode.dt.center.push(node.id) + + } else if (row > 0) { + const preXNode = data.get('wp_' + (row - 1) + '_' + (col)) + node.dt.center.push(preXNode.id) + preXNode.dt.center.push(node.id) + + } else if (col > 0) { + const preYNode = data.get('wp_' + (row) + '_' + (col - 1)) + node.dt.center.push(preYNode.id) + preYNode.dt.center.push(node.id) + } } } diff --git a/src/modules/measure/MeasureRenderer.ts b/src/modules/measure/MeasureRenderer.ts index 71be360..0bfd928 100644 --- a/src/modules/measure/MeasureRenderer.ts +++ b/src/modules/measure/MeasureRenderer.ts @@ -31,7 +31,7 @@ export default class MeasureRenderer extends BaseRenderer { 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) + readonly defaultRotation: THREE.Vector3 = new THREE.Vector3(0, 0, 0) constructor(itemTypeName: string) { super(itemTypeName) @@ -97,109 +97,109 @@ export default class MeasureRenderer extends BaseRenderer { return obj } - appendToScene(...objects: THREE.Object3D[]) { - if (!this.group || this.group.parent !== this.tempViewport.scene.scene) { - if (this.group && this.group.parent !== this.tempViewport.scene.scene) { - // 幻影加载问题 - this.group.parent.removeFromParent() - } - - this.group = new THREE.Group() - this.group.name = MeasureRenderer.GROUP_NAME - this.tempViewport?.scene.add(this.group) - } - - const dragObjects = objects.filter(obj => !!obj.userData.draggable) - //this.tempViewport.dragControl.setDragObjects(dragObjects, 'push') - - this.group.add(...objects) - } - - afterCreateOrUpdateLine(start: ItemJson, end: ItemJson, type: LinkType, option: RendererCudOption, object: THREE.Object3D) { - super.afterCreateOrUpdateLine(start, end, type, option, object) - - const startPoint = this.tempViewport?.entityManager.findObjectById(start.id) - const endPoint = this.tempViewport?.entityManager.findObjectById(end.id) - - const p0 = startPoint.position - const p1 = endPoint.position - - const dist = p0.distanceTo(p1) - const label = numberToString(dist) + ' m' - - const position = new THREE.Vector3().addVectors(p0, p1).multiplyScalar(0.5) - let labelObj: Text | CSS2DObject | undefined = object.userData.labelObj - if (!labelObj || !labelObj.parent) { - labelObj = this.createLabel(label) - this.group.add(labelObj) - object.userData.labelObj = labelObj - } - - labelObj.position.set(position.x, position.y + 0.3, position.z - 0.2) - - if (this.useHtmlLabel) { - labelObj.element.innerHTML = label - - } else { - // 让文本朝向摄像机 - labelObj.quaternion.copy(this.tempViewport.camera.quaternion) - labelObj.text = label - labelObj.sync() - } - } - - afterDeleteLine(start: ItemJson, end: ItemJson, type: LinkType, option: RendererCudOption, object: THREE.Object3D) { - super.afterDeleteLine(start, end, type, option, object) - - // 删除标签 - const labelObj = object.userData?.labelObj - if (labelObj && labelObj.parent) { - labelObj.parent.remove(labelObj) - } - } - - /** - * 创建标签 - */ - createLabel(text: string): Text | CSS2DObject { - if (this.useHtmlLabel) { - const div = document.createElement('div') - div.className = 'css2dObjectLabel' - div.innerHTML = text - div.style.padding = '5px 8px' - div.style.color = '#fff' - div.style.fontSize = '14px' - div.style.position = 'absolute' - div.style.backgroundColor = 'rgba(25, 25, 25, 0.3)' - div.style.borderRadius = '12px' - div.style.top = '0px' - div.style.left = '0px' - // div.style.pointerEvents = 'none' //避免HTML元素影响场景的鼠标事件 - const obj = new CSS2DObject(div) - obj.name = MeasureRenderer.LABEL_NAME - return obj - - } else { - const label = new Text() - label.text = text - label.font = SimSunTTF - label.fontSize = 0.4 - label.color = '#333333' - label.opacity = 0.8 - label.padding = 0.2 - label.anchorX = 'center' - label.anchorY = 'middle' - label.depthOffset = 1 - label.backgroundColor = '#000000' // 黑色背景 - label.backgroundOpacity = 0.6 // 背景半透明 - label.padding = 0.2 // 内边距 - label.material.depthTest = false - label.name = MeasureRenderer.LABEL_NAME - - label.sync() - return label - } - } + // appendToScene(...objects: THREE.Object3D[]) { + // if (!this.group || this.group.parent !== this.tempViewport.scene.scene) { + // if (this.group && this.group.parent !== this.tempViewport.scene.scene) { + // // 幻影加载问题 + // this.group.parent.removeFromParent() + // } + // + // this.group = new THREE.Group() + // this.group.name = MeasureRenderer.GROUP_NAME + // this.tempViewport?.scene.add(this.group) + // } + // + // const dragObjects = objects.filter(obj => !!obj.userData.draggable) + // //this.tempViewport.dragControl.setDragObjects(dragObjects, 'push') + // + // this.group.add(...objects) + // } + // + // afterCreateOrUpdateLine(start: ItemJson, end: ItemJson, type: LinkType, option: RendererCudOption, object: THREE.Object3D) { + // super.afterCreateOrUpdateLine(start, end, type, option, object) + // + // const startPoint = this.tempViewport?.entityManager.findObjectById(start.id) + // const endPoint = this.tempViewport?.entityManager.findObjectById(end.id) + // + // const p0 = startPoint.position + // const p1 = endPoint.position + // + // const dist = p0.distanceTo(p1) + // const label = numberToString(dist) + ' m' + // + // const position = new THREE.Vector3().addVectors(p0, p1).multiplyScalar(0.5) + // let labelObj: Text | CSS2DObject | undefined = object.userData.labelObj + // if (!labelObj || !labelObj.parent) { + // labelObj = this.createLabel(label) + // this.group.add(labelObj) + // object.userData.labelObj = labelObj + // } + // + // labelObj.position.set(position.x, position.y + 0.3, position.z - 0.2) + // + // if (this.useHtmlLabel) { + // labelObj.element.innerHTML = label + // + // } else { + // // 让文本朝向摄像机 + // labelObj.quaternion.copy(this.tempViewport.camera.quaternion) + // labelObj.text = label + // labelObj.sync() + // } + // } + // + // afterDeleteLine(start: ItemJson, end: ItemJson, type: LinkType, option: RendererCudOption, object: THREE.Object3D) { + // super.afterDeleteLine(start, end, type, option, object) + // + // // 删除标签 + // const labelObj = object.userData?.labelObj + // if (labelObj && labelObj.parent) { + // labelObj.parent.remove(labelObj) + // } + // } + // + // /** + // * 创建标签 + // */ + // createLabel(text: string): Text | CSS2DObject { + // if (this.useHtmlLabel) { + // const div = document.createElement('div') + // div.className = 'css2dObjectLabel' + // div.innerHTML = text + // div.style.padding = '5px 8px' + // div.style.color = '#fff' + // div.style.fontSize = '14px' + // div.style.position = 'absolute' + // div.style.backgroundColor = 'rgba(25, 25, 25, 0.3)' + // div.style.borderRadius = '12px' + // div.style.top = '0px' + // div.style.left = '0px' + // // div.style.pointerEvents = 'none' //避免HTML元素影响场景的鼠标事件 + // const obj = new CSS2DObject(div) + // obj.name = MeasureRenderer.LABEL_NAME + // return obj + // + // } else { + // const label = new Text() + // label.text = text + // label.font = SimSunTTF + // label.fontSize = 0.4 + // label.color = '#333333' + // label.opacity = 0.8 + // label.padding = 0.2 + // label.anchorX = 'center' + // label.anchorY = 'middle' + // label.depthOffset = 1 + // label.backgroundColor = '#000000' // 黑色背景 + // label.backgroundOpacity = 0.6 // 背景半透明 + // label.padding = 0.2 // 内边距 + // label.material.depthTest = false + // label.name = MeasureRenderer.LABEL_NAME + // + // label.sync() + // return label + // } + // } dispose() { super.dispose()