From 5b10ecbdeb8828b65cbf66417ddca2d2547083b9 Mon Sep 17 00:00:00 2001 From: luoyifan Date: Tue, 27 May 2025 13:12:11 +0800 Subject: [PATCH] itemType define --- src/designer/Viewport.ts | 67 ++++++------ src/model/ModelUtils.ts | 14 +-- src/model/WorldModel.ts | 2 +- src/model/itemType/ItemTypeBase.ts | 29 ++++++ src/model/itemType/ItemTypeDefine.ts | 131 ++++++++++++++++++++++++ src/model/itemType/ItemTypeLineBase.ts | 126 +++++++++++++++++++++++ src/model/itemType/line/LineMeta.ts | 7 ++ src/model/itemType/measure/Measure.ts | 95 +++++++++++++++++ src/model/itemType/measure/MeasureMeta.ts | 9 ++ src/model/itemType/point/PointMeta.ts | 7 ++ src/model/itemType/store/QueueMeta.ts | 7 ++ src/model/itemTypeDefine/ItemTypeBase.ts | 29 ------ src/model/itemTypeDefine/ItemTypeDefine.ts | 131 ------------------------ src/model/itemTypeDefine/ItemTypeLineBase.ts | 127 ----------------------- src/model/itemTypeDefine/line/LineMeta.ts | 7 -- src/model/itemTypeDefine/measure/Measure.ts | 71 ------------- src/model/itemTypeDefine/measure/MeasureMeta.ts | 9 -- src/model/itemTypeDefine/point/PointMeta.ts | 7 -- src/model/itemTypeDefine/store/QueueMeta.ts | 7 -- 19 files changed, 455 insertions(+), 427 deletions(-) create mode 100644 src/model/itemType/ItemTypeBase.ts create mode 100644 src/model/itemType/ItemTypeDefine.ts create mode 100644 src/model/itemType/ItemTypeLineBase.ts create mode 100644 src/model/itemType/line/LineMeta.ts create mode 100644 src/model/itemType/measure/Measure.ts create mode 100644 src/model/itemType/measure/MeasureMeta.ts create mode 100644 src/model/itemType/point/PointMeta.ts create mode 100644 src/model/itemType/store/QueueMeta.ts delete mode 100644 src/model/itemTypeDefine/ItemTypeBase.ts delete mode 100644 src/model/itemTypeDefine/ItemTypeDefine.ts delete mode 100644 src/model/itemTypeDefine/ItemTypeLineBase.ts delete mode 100644 src/model/itemTypeDefine/line/LineMeta.ts delete mode 100644 src/model/itemTypeDefine/measure/Measure.ts delete mode 100644 src/model/itemTypeDefine/measure/MeasureMeta.ts delete mode 100644 src/model/itemTypeDefine/point/PointMeta.ts delete mode 100644 src/model/itemTypeDefine/store/QueueMeta.ts diff --git a/src/designer/Viewport.ts b/src/designer/Viewport.ts index fbecc70..95a956a 100644 --- a/src/designer/Viewport.ts +++ b/src/designer/Viewport.ts @@ -1,6 +1,16 @@ import _ from 'lodash' import * as THREE from 'three' -import { AxesHelper, GridHelper, OrthographicCamera, Raycaster, Scene, Vector3, WebGLRenderer } from 'three' +import { + AxesHelper, + GridHelper, + Mesh, + type Object3D, + OrthographicCamera, + Raycaster, + Scene, + Vector3, + WebGLRenderer +} from 'three' import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls' import EsDragControls from './model2DEditor/EsDragControls' import Stats from 'three/examples/jsm/libs/stats.module' @@ -23,7 +33,7 @@ export default class Viewport { scene: Scene camera: OrthographicCamera renderer: WebGLRenderer - axesHelper: AxesHelper + axesHelper: GridHelper gridHelper: GridHelper statsControls: Stats controls: OrbitControls @@ -139,30 +149,35 @@ export default class Viewport { this.initMode2DCamera() // 辅助线 - this.axesHelper = new THREE.AxesHelper(3) + const axesHelper = new THREE.GridHelper(1000, 2) + axesHelper.material.color.setHex(0x000000) + axesHelper.material.linewidth = 2 + // @ts-ignore + axesHelper.material.vertexColors = false + this.axesHelper = axesHelper this.scene.add(this.axesHelper) - this.gridHelper = new THREE.GridHelper(500, 500) - const gridHelper = this.gridHelper - gridHelper.material = new THREE.LineBasicMaterial({ - color: 0x888888, - opacity: 0.8, - transparent: true - }) + const gridHelper = new THREE.GridHelper(1000, 1000) + gridHelper.material.color.setHex(0x999999) + gridHelper.material.opacity = 0.8 + gridHelper.material.transparent = true + // @ts-ignore + gridHelper.material.vertexColors = false - scene.add(gridHelper) + this.gridHelper = gridHelper + this.scene.add(this.gridHelper) // 光照 - const ambientLight = new THREE.AmbientLight(0xffffff, 1.5) + const ambientLight = new THREE.AmbientLight(0xffffff, 0.8) scene.add(ambientLight) - const directionalLight = new THREE.DirectionalLight(0xffffff, 1.5) - directionalLight.position.set(5, 5, 5).multiplyScalar(3) - directionalLight.castShadow = true - scene.add(directionalLight) - - const hemisphereLight = new THREE.HemisphereLight(0xffffff, 0x444444, 1) - scene.add(hemisphereLight) + // const directionalLight = new THREE.DirectionalLight(0xffffff, 1.5) + // directionalLight.position.set(5, 5, 5).multiplyScalar(3) + // directionalLight.castShadow = true + // scene.add(directionalLight) + // + // const hemisphereLight = new THREE.HemisphereLight(0xffffff, 0x444444, 1) + // scene.add(hemisphereLight) // 性能监控 const statsControls = new Stats() @@ -174,16 +189,6 @@ export default class Viewport { viewerDom.appendChild(statsControls.dom) $(statsControls.dom).children().css('height', '28px') - // 创建几何体和材质 - const geometry = new THREE.BoxGeometry(1, 1, 1) - const material = new THREE.MeshStandardMaterial({ - color: 0xcccccc, - metalness: 0.9, - roughness: 0.1 - }) - const cube = new THREE.Mesh(geometry, material) - scene.add(cube) - this.animate() // 监听事件 @@ -372,9 +377,9 @@ export default class Viewport { const fadeStartDistance = 15 // 开始淡出的距离 // 计算透明度(0~1) - let opacity = 1 + let opacity = 0.8 if (cameraDistance > fadeStartDistance) { - opacity = 1 - Math.min((cameraDistance - fadeStartDistance) / (maxVisibleDistance - fadeStartDistance), 1) + opacity = 0.8 - Math.min((cameraDistance - fadeStartDistance) / (maxVisibleDistance - fadeStartDistance) * 0.8, 0.8) } // 修改网格材质透明度 diff --git a/src/model/ModelUtils.ts b/src/model/ModelUtils.ts index c73e089..6a1fd48 100644 --- a/src/model/ModelUtils.ts +++ b/src/model/ModelUtils.ts @@ -1,5 +1,5 @@ import * as THREE from 'three' -import type { ItemJson } from '@/model/itemTypeDefine/ItemTypeDefine.ts' +import type { ItemJson, ItemTypeDefineOption } from '@/model/itemType/ItemTypeDefine.ts' import { getAllItemTypes, getItemTypeByName } from '@/runtime/DefineItemType.ts' export function loadSceneFromJson(scene: THREE.Scene, items: ItemJson[]) { @@ -7,15 +7,15 @@ export function loadSceneFromJson(scene: THREE.Scene, items: ItemJson[]) { const object3ds = loadObject3DFromJson(items) // 通知所有加载的对象, 模型加载完成 - getAllItemTypes().forEach(itemType => { - if (typeof itemType.clazz.afterLoadComplete === 'function') { - itemType.clazz.afterLoadComplete(object3ds) + getAllItemTypes().forEach((itemType: ItemTypeDefineOption) => { + const ret = itemType.clazz.afterLoadComplete(object3ds) + if (ret && Array.isArray(ret)) { + // 如果返回值是数组,则合并到 object3ds 中 + object3ds.push(...ret) } }) - object3ds.forEach(object3D => { - scene.add(object3D) - }) + scene.add(...object3ds) // 通知所有加载的对象, 模型加载完成 getAllItemTypes().forEach(itemType => { diff --git a/src/model/WorldModel.ts b/src/model/WorldModel.ts index f860a91..c8b1b85 100644 --- a/src/model/WorldModel.ts +++ b/src/model/WorldModel.ts @@ -6,7 +6,7 @@ import { Scene } from 'three' import type Viewport from '@/designer/Viewport.ts' import { loadSceneFromJson } from '@/model/ModelUtils.ts' -import MeasureMeta from './itemTypeDefine/measure/MeasureMeta' +import MeasureMeta from './itemType/measure/MeasureMeta' /** * 世界模型 diff --git a/src/model/itemType/ItemTypeBase.ts b/src/model/itemType/ItemTypeBase.ts new file mode 100644 index 0000000..c042687 --- /dev/null +++ b/src/model/itemType/ItemTypeBase.ts @@ -0,0 +1,29 @@ +import { type Object3D } from 'three' +import type WorldModel from '@/model/WorldModel.ts' +import type { ItemJson, ItemTypeDefineOption } from '@/model/itemType/ItemTypeDefine.ts' +import * as THREE from 'three' + +export default abstract class ItemTypeBase { + name: string + option: ItemTypeDefineOption + worldModel: WorldModel + + public init(worldModel: WorldModel) { + this.worldModel = worldModel + + // 初始化方法,子类可以重写 + return Promise.resolve() + } + + abstract loadFromJson(item: ItemJson): undefined | THREE.Object3D + + afterLoadComplete(objects: THREE.Object3D[]): THREE.Object3D[] { + return [] + } + + /** + * 添加到 scene 后的回调 + */ + afterAddScene(scene: THREE.Scene, objects: THREE.Object3D[]): void { + } +} \ No newline at end of file diff --git a/src/model/itemType/ItemTypeDefine.ts b/src/model/itemType/ItemTypeDefine.ts new file mode 100644 index 0000000..399d7bf --- /dev/null +++ b/src/model/itemType/ItemTypeDefine.ts @@ -0,0 +1,131 @@ +import type ItemTypeBase from '@/model/itemType/ItemTypeBase.ts' + +export type ActionType = +/** + * 线类型 + */ + 'ln' | + /** + * 点类型 + */ + 'pt' | + /** + * 物流运输单元 + */ + 'fl' | + /** + * 分组单元,仅用于分组 + */ + 'gp' + +export interface ItemTypeDefineOption { + name: string + label: string + actionType: ActionType + clazz: ItemTypeBase +} + +/** + * 定义物体类型的元数据 + * 举例: + * { + * id: 'p1', // 物体ID, 唯一标识, 需保证唯一, three.js 中的 uuid + * t: 'measure', // 物体类型, measure表示测量, 需交给 itemType.name == 'measure' 的组件处理 + * a: 'ln', // 交互类型, ln表示线点操作, pt 表示点操作 + * l: '测量1', // 标签名称, 显示用 + * c: '#ff0000', // 颜色, 显示用. 十六进制颜色值, three.js 中的材质颜色 + * tf: [ // 变换矩阵, 3x3矩阵, 采用Y轴向上为正, X轴向右, Z轴向前的右手坐标系 + * [-9.0, 0, -1.0], // 平移向量 position + * [0, 0, 0], // 旋转向量 rotation, 表示绕Y轴旋转的角度, 单位为度。对应 three.js 应进行"角度"转"弧度"的换算 + * [0.25, 0.1, 0.25] // 缩放向量 scale + * ], + * dt: { // 用户数据, 可自定义, 一般用在 three.js 的 userData 中 + * link: ['p2'], // 用于 a='ln' 的测量线段, 关联的点对象(uuid) + * center: [], // 物流关联对象(uuid) + * in: [], // 物流入方向关联的对象(uuid) + * out: [] // 物流出方向关联的对象(uuid) + * } + * } + */ +export interface ItemJson { + /** + * 物体名称, 显示用, 最后初始化到 three.js 的 name 中, 可以不设置, 可以不唯一 + */ + name?: string + + /** + * 对应 three.js 中的 uuid, 物体ID, 唯一标识, 需保证唯一 + */ + id: string + + /** + * 物体类型, 对应 defineItemType.name + */ + t: string + + /** + * 交互类型 + */ + a: ActionType + + /** + * 标签名称, 显示用, 最后初始化到 three.js 的 userData.label 中 + */ + l?: string + + /** + * 颜色, 最后初始化到 three.js 的 userData.color 中 + */ + c: string + + /** + * 变换矩阵, 3x3矩阵, 采用Y轴向上为正, X轴向右, Z轴向前的右手坐标系 + */ + tf: [ + /** + * 平移向量 position, 三维坐标 + */ + [number, number, number], + /** + * 旋转向量 rotation, 表示绕Y轴旋转的角度, 单位为度。对应 three.js 应进行"角度"转"弧度"的换算 + */ + [number, number, number], + /** + * 缩放向量 scale, 三维缩放比例 + */ + [number, number, number], + ] + + /** + * 用户数据, 可自定义, 一般用在 three.js 的 userData 中 + */ + dt: { + /** + * 测量线段关联的点对象(uuid), 仅在 a='ln' 时有效 + */ + link?: string[] + + /** + * 物流关联对象(uuid) + */ + center?: string[] + /** + * 物流入方向关联的对象(uuid) + */ + in?: string[] + /** + * 物流出方向关联的对象(uuid) + */ + out?: string[] + + /** + * 其他自定义数据, 可以存储任何数据 + */ + [key: string]: any + }, + + /** + * 子元素, 用于分组等, 可以为空数组 + */ + items: ItemJson[] +} \ No newline at end of file diff --git a/src/model/itemType/ItemTypeLineBase.ts b/src/model/itemType/ItemTypeLineBase.ts new file mode 100644 index 0000000..d3d9e1c --- /dev/null +++ b/src/model/itemType/ItemTypeLineBase.ts @@ -0,0 +1,126 @@ +import * as THREE from 'three' +import ItemTypeBase from '@/model/itemType/ItemTypeBase.ts' +import type { ItemJson } from '@/model/itemType/ItemTypeDefine.ts' +import type WorldModel from '@/model/WorldModel.ts' + +/** + * ILineType 接口定义了线类型的基本方法 + * 用于创建点和线 + */ +export default abstract class ItemTypeLineBase extends ItemTypeBase { + + /** + * 所有点的数组 + */ + pointArray: THREE.Object3D[] = [] + + /** + * 所有连接线的数组 + */ + linkArray: THREE.Object3D[] = [] + + public init(worldModel: WorldModel) { + return super.init(worldModel).then(() => { + // 初始化方法,子类可以重写 + this.pointArray.length = 0 + this.linkArray.length = 0 + }) + } + + afterLoadGroup(group: THREE.Group): void { + } + + afterLoadLine(line: THREE.Line): void { + } + + afterLoadPoint(point: THREE.Object3D): void { + } + + afterAddScene(scene: THREE.Scene, objects: THREE.Object3D[]) { + super.afterAddScene(scene, objects) + + // 为所有的 pointArray 连接线 + for (let i = 0; i < this.pointArray.length; i++) { + const startPoint = this.pointArray[i] + + // 找到这个元素的 userData.link 数组 + const linkArray: string[] = startPoint.userData.link || [] + + for (let j = 0; j < linkArray.length; j++) { + const linkId = linkArray[j] + // 在 pointArray 中查找对应的点 + const endPoint = this.pointArray.find(p => p.uuid === linkId) + if (!endPoint) { + console.warn('not found link point uuid=${}', linkId) + continue + } + + const line = this.createLine() + const geom = line.geometry + geom.setFromPoints([startPoint.position, endPoint.position]) + + if (startPoint.parent) { + startPoint.parent.add(line) + } else { + scene.add(line) + } + + this.afterLoadLine(line) + this.linkArray.push(line) + } + } + } + + override loadFromJson(item: ItemJson): undefined | THREE.Object3D { + if (item.a === 'gp') { + // gp 是为了分组而存在的 + const group = new THREE.Group() + group.name = item.name + group.uuid = item.id || THREE.MathUtils.generateUUID() + group.userData = _.cloneDeep(item.dt) || {} + group.userData.type = item.t + group.userData.actionType = item.a + group.userData.label = item.l + group.userData.color = item.c + + this.afterLoadGroup(group) + return group + } + + // 其他情况都是 ln + else if (item.a === 'ln') { + const position = new THREE.Vector3( + item.tf[0][0], + item.tf[0][1], + item.tf[0][2] + ) + + const point = this.createPoint(position) + point.name = item.name + point.uuid = item.id || THREE.MathUtils.generateUUID() + point.userData = _.cloneDeep(item.dt) || {} + point.userData.type = item.t + point.userData.actionType = item.a + point.userData.label = item.l + point.userData.color = item.c + + point.rotation.set( + THREE.MathUtils.degToRad(item.tf[1][0]), + THREE.MathUtils.degToRad(item.tf[1][1]), + THREE.MathUtils.degToRad(item.tf[1][2]) + ) + + point.scale.set(item.tf[2][0], item.tf[2][1], item.tf[2][2]) + this.pointArray.push(point) + + this.afterLoadPoint(point) + return point + } + + console.error('ItemTypeLineBase.loadFromJson: Unsupported', item) + } + + abstract createPoint(position: THREE.Vector3): THREE.Object3D + + abstract createLine(): THREE.Line +} \ No newline at end of file diff --git a/src/model/itemType/line/LineMeta.ts b/src/model/itemType/line/LineMeta.ts new file mode 100644 index 0000000..7f6fc25 --- /dev/null +++ b/src/model/itemType/line/LineMeta.ts @@ -0,0 +1,7 @@ +import { defineItem } from '@/runtime/DefineItem.ts' + +export default defineItem({ + name: 'line', + label: '辅助线', + category: 'line' +}) \ No newline at end of file diff --git a/src/model/itemType/measure/Measure.ts b/src/model/itemType/measure/Measure.ts new file mode 100644 index 0000000..5119f50 --- /dev/null +++ b/src/model/itemType/measure/Measure.ts @@ -0,0 +1,95 @@ +import * as THREE from 'three' +import ItemTypeLineBase from '@/model/itemType/ItemTypeLineBase.ts' +import { Material, Object3D, Scene } from 'three' +import WorldModel from '@/model/WorldModel.ts' + +export const GROUP_NAME = 'measure-group' +export const POINT_NAME = 'measure_point' +export const LABEL_NAME = 'measure_label' +export const LINE_NAME = 'measure_line' + +export default class Measure extends ItemTypeLineBase { + /** + * 当前测绘内容组, 所有测量点、线、标签都在这个组中. 但不包括临时点、线 + */ + group: THREE.Group + + pointMaterial!: Material + + lineMaterial!: Material + + override init(worldModel: WorldModel): Promise { + super.init(worldModel) + + this.lineMaterial = new THREE.LineBasicMaterial({ + color: 0xE63C17, + linewidth: 2, + opacity: 0.9, + transparent: true, + side: THREE.DoubleSide, + depthWrite: false, + depthTest: false + }) + + this.pointMaterial = new THREE.MeshBasicMaterial({ color: 0x303133, transparent: true, opacity: 0.9 }) + + this.group = new THREE.Group() + this.group.name = GROUP_NAME + + return Promise.resolve() + } + + // 创建完线之后,创建 label + afterLoadLine(line: THREE.Line) { + super.afterLoadLine(line) + } + + + afterLoadGroup(group: THREE.Group) { + super.afterLoadGroup(group) + if (this.group) { + // 如果已经有 group,则忽略 + return + } + this.group = group + } + + afterLoadComplete(objects: THREE.Object3D[]): THREE.Object3D[] { + // 如果没有 group,则创建一个新的 group + if (!this.group) { + this.group = new THREE.Group() + this.group.name = GROUP_NAME + } + + return [this.group] + } + + /** + * 创建测量点 + */ + createPoint(position?: THREE.Vector3): THREE.Object3D { + const p = position + const scale = 0.25 + + const tt = new THREE.BoxGeometry(1, 1, 1) + const obj = new THREE.Mesh(tt, this.pointMaterial) + obj.scale.set(scale, 0.1, scale) + if (p) { + obj.position.set(p.x, p.y, p.z) + } + obj.name = POINT_NAME + return obj + } + + /** + * 创建测量线 + */ + createLine(): THREE.Line { + const geom = new THREE.BufferGeometry() + const obj = new THREE.Line(geom, this.lineMaterial) + obj.frustumCulled = false + obj.name = LINE_NAME + obj.uuid = THREE.MathUtils.generateUUID() + return obj + } +} \ No newline at end of file diff --git a/src/model/itemType/measure/MeasureMeta.ts b/src/model/itemType/measure/MeasureMeta.ts new file mode 100644 index 0000000..42220ec --- /dev/null +++ b/src/model/itemType/measure/MeasureMeta.ts @@ -0,0 +1,9 @@ +import { defineItemType } from '@/runtime/DefineItemType.ts' +import Measure from '@/model/itemType/measure/Measure.ts' + +export default defineItemType({ + name: 'measure', + label: '测量距离', + actionType: 'ln', + clazz: new Measure() +}) \ No newline at end of file diff --git a/src/model/itemType/point/PointMeta.ts b/src/model/itemType/point/PointMeta.ts new file mode 100644 index 0000000..650f231 --- /dev/null +++ b/src/model/itemType/point/PointMeta.ts @@ -0,0 +1,7 @@ +import { defineItem } from '@/runtime/DefineItem.ts' + +export default defineItem({ + name: 'point', + label: '辅助点', + category: 'point' +}) \ No newline at end of file diff --git a/src/model/itemType/store/QueueMeta.ts b/src/model/itemType/store/QueueMeta.ts new file mode 100644 index 0000000..4ab06eb --- /dev/null +++ b/src/model/itemType/store/QueueMeta.ts @@ -0,0 +1,7 @@ +import { defineItem } from '@/runtime/DefineItem.ts' + +export default defineItem({ + name: 'queue', + label: '暂存区', + category: 'store' +}) \ No newline at end of file diff --git a/src/model/itemTypeDefine/ItemTypeBase.ts b/src/model/itemTypeDefine/ItemTypeBase.ts deleted file mode 100644 index a825ca9..0000000 --- a/src/model/itemTypeDefine/ItemTypeBase.ts +++ /dev/null @@ -1,29 +0,0 @@ -import { type Object3D } from 'three' -import type WorldModel from '@/model/WorldModel.ts' -import type { ItemJson, ItemTypeDefineOption } from '@/model/itemTypeDefine/ItemTypeDefine.ts' -import * as THREE from 'three' - -export default abstract class ItemTypeBase { - name: string - option: ItemTypeDefineOption - worldModel: WorldModel - - public init(worldModel: WorldModel) { - this.worldModel = worldModel - - // 初始化方法,子类可以重写 - return Promise.resolve() - } - - abstract loadFromJson(item: ItemJson): undefined | THREE.Object3D - - afterLoadComplete(objects: THREE.Object3D[]): THREE.Object3D[] { - return [] - } - - /** - * 添加到 scene 后的回调 - */ - afterAddScene(scene: THREE.Scene, objects: THREE.Object3D[]): void { - } -} \ No newline at end of file diff --git a/src/model/itemTypeDefine/ItemTypeDefine.ts b/src/model/itemTypeDefine/ItemTypeDefine.ts deleted file mode 100644 index 8fd5fd3..0000000 --- a/src/model/itemTypeDefine/ItemTypeDefine.ts +++ /dev/null @@ -1,131 +0,0 @@ -import type ItemTypeBase from '@/model/itemTypeDefine/ItemTypeBase.ts' - -export type ActionType = -/** - * 线类型 - */ - 'ln' | - /** - * 点类型 - */ - 'pt' | - /** - * 物流运输单元 - */ - 'fl' | - /** - * 分组单元,仅用于分组 - */ - 'gp' - -export interface ItemTypeDefineOption { - name: string - label: string - actionType: ActionType - clazz: ItemTypeBase -} - -/** - * 定义物体类型的元数据 - * 举例: - * { - * id: 'p1', // 物体ID, 唯一标识, 需保证唯一, three.js 中的 uuid - * t: 'measure', // 物体类型, measure表示测量, 需交给 itemType.name == 'measure' 的组件处理 - * a: 'ln', // 交互类型, ln表示线点操作, pt 表示点操作 - * l: '测量1', // 标签名称, 显示用 - * c: '#ff0000', // 颜色, 显示用. 十六进制颜色值, three.js 中的材质颜色 - * tf: [ // 变换矩阵, 3x3矩阵, 采用Y轴向上为正, X轴向右, Z轴向前的右手坐标系 - * [-9.0, 0, -1.0], // 平移向量 position - * [0, 0, 0], // 旋转向量 rotation, 表示绕Y轴旋转的角度, 单位为度。对应 three.js 应进行"角度"转"弧度"的换算 - * [0.25, 0.1, 0.25] // 缩放向量 scale - * ], - * dt: { // 用户数据, 可自定义, 一般用在 three.js 的 userData 中 - * link: ['p2'], // 用于 a='ln' 的测量线段, 关联的点对象(uuid) - * center: [], // 物流关联对象(uuid) - * in: [], // 物流入方向关联的对象(uuid) - * out: [] // 物流出方向关联的对象(uuid) - * } - * } - */ -export interface ItemJson { - /** - * 物体名称, 显示用, 最后初始化到 three.js 的 name 中, 可以不设置, 可以不唯一 - */ - name?: string - - /** - * 对应 three.js 中的 uuid, 物体ID, 唯一标识, 需保证唯一 - */ - id: string - - /** - * 物体类型, 对应 defineItemType.name - */ - t: string - - /** - * 交互类型 - */ - a: ActionType - - /** - * 标签名称, 显示用, 最后初始化到 three.js 的 userData.label 中 - */ - l?: string - - /** - * 颜色, 最后初始化到 three.js 的 userData.color 中 - */ - c: string - - /** - * 变换矩阵, 3x3矩阵, 采用Y轴向上为正, X轴向右, Z轴向前的右手坐标系 - */ - tf: [ - /** - * 平移向量 position, 三维坐标 - */ - [number, number, number], - /** - * 旋转向量 rotation, 表示绕Y轴旋转的角度, 单位为度。对应 three.js 应进行"角度"转"弧度"的换算 - */ - [number, number, number], - /** - * 缩放向量 scale, 三维缩放比例 - */ - [number, number, number], - ] - - /** - * 用户数据, 可自定义, 一般用在 three.js 的 userData 中 - */ - dt: { - /** - * 测量线段关联的点对象(uuid), 仅在 a='ln' 时有效 - */ - link?: string[] - - /** - * 物流关联对象(uuid) - */ - center?: string[] - /** - * 物流入方向关联的对象(uuid) - */ - in?: string[] - /** - * 物流出方向关联的对象(uuid) - */ - out?: string[] - - /** - * 其他自定义数据, 可以存储任何数据 - */ - [key: string]: any - }, - - /** - * 子元素, 用于分组等, 可以为空数组 - */ - items: ItemJson[] -} \ No newline at end of file diff --git a/src/model/itemTypeDefine/ItemTypeLineBase.ts b/src/model/itemTypeDefine/ItemTypeLineBase.ts deleted file mode 100644 index b1a8618..0000000 --- a/src/model/itemTypeDefine/ItemTypeLineBase.ts +++ /dev/null @@ -1,127 +0,0 @@ -import * as THREE from 'three' -import ItemTypeBase from '@/model/itemTypeDefine/ItemTypeBase.ts' -import type { ItemJson } from '@/model/itemTypeDefine/ItemTypeDefine.ts' -import type WorldModel from '@/model/WorldModel.ts' - -/** - * ILineType 接口定义了线类型的基本方法 - * 用于创建点和线 - */ -export default abstract class ItemTypeLineBase extends ItemTypeBase { - - /** - * 所有点的数组 - */ - pointArray: THREE.Object3D[] = [] - - /** - * 所有连接线的数组 - */ - linkArray: THREE.Object3D[] = [] - - public init(worldModel: WorldModel) { - return super.init(worldModel).then(() => { - // 初始化方法,子类可以重写 - this.pointArray.length = 0 - this.linkArray.length = 0 - }) - } - - afterLoadGroup(group: THREE.Group): void { - } - - afterLoadLine(line: THREE.Line): void { - } - - afterLoadPoint(point: THREE.Object3D): void { - } - - - afterAddScene(scene: THREE.Scene, objects: THREE.Object3D[]) { - super.afterAddScene(scene, objects) - - // 为所有的 pointArray 连接线 - for (let i = 0; i < this.pointArray.length; i++) { - const startPoint = this.pointArray[i] - - // 找到这个元素的 userData.link 数组 - const linkArray: string[] = startPoint.userData.link || [] - - for (let j = 0; j < linkArray.length; j++) { - const linkId = linkArray[j] - // 在 pointArray 中查找对应的点 - const endPoint = this.pointArray.find(p => p.uuid === linkId) - if (!endPoint) { - console.warn('not found link point uuid=${}', linkId) - continue - } - - const line = this.createLine() - const geom = line.geometry - geom.setFromPoints([startPoint.position, endPoint.position]) - - if (startPoint.parent) { - startPoint.parent.add(line) - } else { - scene.add(line) - } - - this.afterLoadLine(line) - this.linkArray.push(line) - } - } - } - - override loadFromJson(item: ItemJson): undefined | THREE.Object3D { - if (item.a === 'gp') { - // gp 是为了分组而存在的 - const group = new THREE.Group() - group.name = item.name - group.uuid = item.id || THREE.MathUtils.generateUUID() - group.userData = _.cloneDeep(item.dt) || {} - group.userData.type = item.t - group.userData.actionType = item.a - group.userData.label = item.l - group.userData.color = item.c - - this.afterLoadGroup(group) - return group - } - - // 其他情况都是 ln - else if (item.a === 'ln') { - const position = new THREE.Vector3( - item.tf[0][0], - item.tf[0][1], - item.tf[0][2] - ) - - const point = this.createPoint(position) - point.name = item.name - point.uuid = item.id || THREE.MathUtils.generateUUID() - point.userData = _.cloneDeep(item.dt) || {} - point.userData.type = item.t - point.userData.actionType = item.a - point.userData.label = item.l - point.userData.color = item.c - - point.rotation.set( - THREE.MathUtils.degToRad(item.tf[1][0]), - THREE.MathUtils.degToRad(item.tf[1][1]), - THREE.MathUtils.degToRad(item.tf[1][2]) - ) - - point.scale.set(item.tf[2][0], item.tf[2][1], item.tf[2][2]) - this.pointArray.push(point) - - this.afterLoadPoint(point) - return point - } - - console.error('ItemTypeLineBase.loadFromJson: Unsupported', item) - } - - abstract createPoint(position: THREE.Vector3): THREE.Object3D - - abstract createLine(): THREE.Line -} \ No newline at end of file diff --git a/src/model/itemTypeDefine/line/LineMeta.ts b/src/model/itemTypeDefine/line/LineMeta.ts deleted file mode 100644 index 7f6fc25..0000000 --- a/src/model/itemTypeDefine/line/LineMeta.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { defineItem } from '@/runtime/DefineItem.ts' - -export default defineItem({ - name: 'line', - label: '辅助线', - category: 'line' -}) \ No newline at end of file diff --git a/src/model/itemTypeDefine/measure/Measure.ts b/src/model/itemTypeDefine/measure/Measure.ts deleted file mode 100644 index 7997496..0000000 --- a/src/model/itemTypeDefine/measure/Measure.ts +++ /dev/null @@ -1,71 +0,0 @@ -import * as THREE from 'three' -import ItemTypeLineBase from '@/model/itemTypeDefine/ItemTypeLineBase.ts' -import type WorldModel from '@/model/WorldModel.ts' -import { Material } from 'three/src/materials/Material' - -export const TYPE_NAME = 'measure' -export const POINT_NAME = 'measure_point' -export const LABEL_NAME = 'measure_label' -export const LINE_NAME = 'measure_line' - -export default class Measure extends ItemTypeLineBase { - /** - * 当前测绘内容组, 所有测量点、线、标签都在这个组中. 但不包括临时点、线 - */ - group: THREE.Group - - pointMaterial!: Material - - lineMaterial!: Material - - override init(worldModel: WorldModel): Promise { - super.init(worldModel) - - this.lineMaterial = new THREE.LineBasicMaterial({ - color: 0xE63C17, - linewidth: 2, - opacity: 0.9, - transparent: true, - side: THREE.DoubleSide, - depthWrite: false, - depthTest: false - }) - - this.pointMaterial = new THREE.MeshBasicMaterial({ color: 0x303133, transparent: true, opacity: 0.9 }) - return Promise.resolve() - } - - // 创建完线之后,创建 label - afterLoadLine(line: THREE.Line) { - super.afterLoadLine(line) - } - - /** - * 创建测量点 - */ - createPoint(position?: THREE.Vector3): THREE.Object3D { - const p = position - const scale = 0.25 - - const tt = new THREE.BoxGeometry(1, 1, 1) - const obj = new THREE.Mesh(tt, this.pointMaterial) - obj.scale.set(scale, 0.1, scale) - if (p) { - obj.position.set(p.x, p.y, p.z) - } - obj.name = POINT_NAME - return obj - } - - /** - * 创建测量线 - */ - createLine(): THREE.Line { - const geom = new THREE.BufferGeometry() - const obj = new THREE.Line(geom, this.lineMaterial) - obj.frustumCulled = false - obj.name = LINE_NAME - obj.uuid = THREE.MathUtils.generateUUID() - return obj - } -} \ No newline at end of file diff --git a/src/model/itemTypeDefine/measure/MeasureMeta.ts b/src/model/itemTypeDefine/measure/MeasureMeta.ts deleted file mode 100644 index 3b7d409..0000000 --- a/src/model/itemTypeDefine/measure/MeasureMeta.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { defineItemType } from '@/runtime/DefineItemType.ts' -import Measure from '@/model/itemTypeDefine/measure/Measure.ts' - -export default defineItemType({ - name: 'measure', - label: '测量距离', - actionType: 'ln', - clazz: new Measure() -}) \ No newline at end of file diff --git a/src/model/itemTypeDefine/point/PointMeta.ts b/src/model/itemTypeDefine/point/PointMeta.ts deleted file mode 100644 index 650f231..0000000 --- a/src/model/itemTypeDefine/point/PointMeta.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { defineItem } from '@/runtime/DefineItem.ts' - -export default defineItem({ - name: 'point', - label: '辅助点', - category: 'point' -}) \ No newline at end of file diff --git a/src/model/itemTypeDefine/store/QueueMeta.ts b/src/model/itemTypeDefine/store/QueueMeta.ts deleted file mode 100644 index 4ab06eb..0000000 --- a/src/model/itemTypeDefine/store/QueueMeta.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { defineItem } from '@/runtime/DefineItem.ts' - -export default defineItem({ - name: 'queue', - label: '暂存区', - category: 'store' -}) \ No newline at end of file