import * as THREE from 'three' import { BasePlane } from '@/types/ModelTypes.ts' /** * 创建一个矩形的 Shape */ export function buildRectangle(width: number, height: number, padding: number[] | number = 0, offsetX = 0, offsetY = 0): THREE.Shape { let pl = 0, pt = 0, pr = 0, pb = 0 if (typeof padding == 'number') { pl = padding pt = padding pr = padding pb = padding } else if (Array.isArray(padding)) { if (padding.length == 1) { pl = padding[0] pt = padding[0] pr = padding[0] pb = padding[0] } else if (padding.length > 1 && padding.length < 4) { pl = padding[0] pt = padding[1] pr = padding[0] pb = padding[1] } else if (padding.length >= 4) { pl = padding[0] pt = padding[1] pr = padding[2] pb = padding[3] } } const shape = new THREE.Shape() shape.moveTo(0 + pl + offsetX, 0 + pb + offsetY) shape.lineTo(width - pr + offsetX, 0 + pb + offsetY) shape.lineTo(width - pr + offsetX, height - pt + offsetY) shape.lineTo(0 + pl + offsetX, height - pt + offsetY) shape.closePath() return shape } /** * 根据自定义的 Shape,通过放样得到一个实体。默认实体的样式是在 front 面放样的。 * * @param {*} shape 自定义的型状 * @param {*} depth 放样深度(放样后的物体厚度) * @param {*} basePlane 放样的基准面。 * @param {*} x 目标定位x * @param {*} y 目标定位y * @param {*} z 目标定位z * @param {*} euler 旋转到目标位 * @param {*} anchor 锚点 * @returns THREE.ExtrudeGeometry */ export function createExtrudeItem(shape: THREE.Shape, depth: number, basePlane: number, x = 0, y = 0, z = 0, euler = null, anchor = new THREE.Vector3(0, 0, 0)) { const geometry = new THREE.ExtrudeGeometry(shape, { steps: 1, depth: -depth, bevelEnabled: false, bevelThickness: 0, bevelSize: 0, bevelOffset: 0, bevelSegments: 0 }) geometry.center() const size = geometry.boundingBox.getSize(new THREE.Vector3()) let dx, dy, dz switch (basePlane) { case BasePlane.LEFT: geometry.rotateY(Math.PI / 2) dx = size.z / 2 dy = size.y / 2 dz = size.x / 2 break case BasePlane.RIGHT: geometry.rotateY(-Math.PI / 2) dx = size.z / 2 dy = size.y / 2 dz = size.x / 2 break case BasePlane.BEHIND: geometry.translate(0, 0, size.z) dx = size.x / 2 dy = size.y / 2 dz = size.z / 2 break case BasePlane.TOP: geometry.rotateZ(Math.PI) geometry.rotateX(Math.PI / 2) geometry.translate(size.x, -size.z, 0) dx = size.x / 2 dy = size.z / 2 dz = size.y / 2 break case BasePlane.BOTTOM: geometry.rotateX(-Math.PI / 2) dx = size.x / 2 dy = size.z / 2 dz = size.y / 2 break default: //BasePlane.FRONT: dx = size.x / 2 dy = size.y / 2 dz = size.z / 2 break } if (euler != null && euler.isEuler) { // 注意,需要先旋转,再平移。 geometry.rotateX(euler.x) geometry.rotateY(euler.y) geometry.rotateZ(euler.z) } geometry.translate(dx + x + anchor.x, dy + y + anchor.y, -dz + z + anchor.z) geometry.center() return geometry }