From 0ae3c9800ad7557ed050a920fcba11a71b8160f6 Mon Sep 17 00:00:00 2001 From: limao Date: Mon, 14 Mar 2022 11:07:37 +0800 Subject: [PATCH 1/3] =?UTF-8?q?refactor:=20=E9=87=8D=E6=9E=84=E5=8F=82?= =?UTF-8?q?=E6=95=B0=E5=8C=96=E6=A8=A1=E5=9E=8B=E8=BF=98=E5=8E=9F=E4=BB=A3?= =?UTF-8?q?=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/utils/helper.ts | 8 +- src/utils/param-model-regen.ts | 151 ++++++++++++++++++++ src/utils/service.ts | 58 +------- src/views/JsonTo3d.vue | 250 +++------------------------------ 4 files changed, 176 insertions(+), 291 deletions(-) create mode 100644 src/utils/param-model-regen.ts diff --git a/src/utils/helper.ts b/src/utils/helper.ts index 8240515..e9cd2c7 100644 --- a/src/utils/helper.ts +++ b/src/utils/helper.ts @@ -1,4 +1,4 @@ -import { IExportParamModelData } from "@manycore/custom-miniapp-sdk"; +import { IExportParamModelData, Number3 } from "@manycore/custom-miniapp-sdk"; /** 发送一次IDP消息并监听相应的返回消息 */ export async function listenIdpMsgOnce(postActionName: string, acceptActionName = postActionName) { @@ -13,7 +13,6 @@ export async function listenIdpMsgOnce(postActionName: string, acceptActionName window.parent.postMessage({ action: postActionName }, '*') }) } - /** 获取最底层的模型 */ export function getFloorModels(paramModel: IExportParamModelData) { const floorModels: IExportParamModelData[] = [] @@ -28,4 +27,9 @@ export function getFloorModels(paramModel: IExportParamModelData) { } recursion(paramModel.subModels) return floorModels +} +/** 获取[x, y, z]格式的数据 */ +export function xyz(o: Number3) { + const { x, y, z } = o + return [x, y, z] as [typeof x, typeof y, typeof z] } \ No newline at end of file diff --git a/src/utils/param-model-regen.ts b/src/utils/param-model-regen.ts new file mode 100644 index 0000000..2ec0b7e --- /dev/null +++ b/src/utils/param-model-regen.ts @@ -0,0 +1,151 @@ +import { ELineType, IExportParamModelData, ILineData, Number2, Number3 } from "@manycore/custom-miniapp-sdk" +import { BufferGeometry, ColorRepresentation, EdgesGeometry, Euler, ExtrudeGeometry, Group, LineBasicMaterial, LineSegments, Mesh, MeshStandardMaterial, Object3D, Shape } from "three" +import { getFloorModels, xyz } from "./helper" +import { getArc2Angle, getArcCenter, getEllArc2Angle } from "./math" +import { ELineType2, ILineData2, IPathData2 } from "./type" + +/** 填充形状数据 */ +export function fillShapeData(model: IExportParamModelData): IExportParamModelData { + const { size } = model; + const center = { x: 0, y: 0, z: 0 } + const resultPoints = [ + { x: center.x - size.x / 2, y: center.y - size.y / 2 }, + { x: center.x - size.x / 2, y: center.y + size.y / 2 }, + { x: center.x + size.x / 2, y: center.y + size.y / 2 }, + { x: center.x + size.x / 2, y: center.y - size.y / 2 }, + ]; + const thickness = size.z; + const path = { + resultPoints, + resultLines: new Array(resultPoints.length).fill({}) + } + const paramPlankPath: any = { path } + return { ...model, thickness, paramPlankPath }; +} +/** 获取形状数据 */ +export function getShapeData(model: IExportParamModelData) { + const { paramPlankPath: { path, holes } } = model + return { path, holes } as unknown as { path: IPathData2, holes: IPathData2[] } +} +/** 形状还原 */ +export function getShape(points: Number2[], lines: ILineData[]) { + const shape = new Shape() + const [startPoint, ...otherPoints] = points + if (points.length === lines.length) otherPoints.push(points[0]) + shape.moveTo(startPoint.x, startPoint.y) + otherPoints.forEach((point, index) => { + const line = lines[index] + const get2p = () => { + const p1 = (points[index]) + const p2 = (point) + return [p1, p2] + } + const getLine = () => line as ILineData2 + switch (line.type as ELineType | ELineType2) { + case ELineType.SEGMENT: + shape.lineTo(point.x, point.y) + break; + // 圆弧还原逻辑 + case ELineType.CIRCLE_ARC: + { + const [p1, p2] = get2p() + const { minorArc, clockwise, radius } = getLine() + const center = getArcCenter(p1, p2, radius, minorArc, !clockwise) + const [startAngle, endAngle] = getArc2Angle(center, p1, p2) + const { x: cx, y: cy } = center + shape.absarc(cx, cy, radius, startAngle, endAngle, clockwise); + } + break; + // 椭圆弧还原逻辑 + case ELineType2.ELLIPSE_ARC: + { + const [p1, p2] = get2p() + const { clockwise, curve2d, curve2d: { a, b, c } } = getLine() + const { x: cx, y: cy } = c + const [startAngle, endAngle] = getEllArc2Angle(p1, p2, !clockwise, curve2d) + shape.absellipse(cx, cy, a, b, startAngle, endAngle, clockwise, 0) + } + break; + + default: shape.lineTo(point.x, point.y) + break; + } + }) + return shape +} +/** 根据模型数据,还原形状 */ +export function getShapeFromModel(model: IExportParamModelData) { + const { path, holes } = getShapeData(model); + const plankShape = getShape(path.resultPoints, path.resultLines); + if (holes) { + plankShape.holes = holes.map(hole => getShape(hole.resultPoints, hole.resultLines)); + } + return plankShape; +} +/** 板件材质设置 */ +export function getPlank(plankShape: Shape, thickness: number) { + return new Mesh( + new ExtrudeGeometry(plankShape, { depth: thickness }), + new MeshStandardMaterial({ color: 'orange' }) + ); +} +/** 描边 */ +export function getEdge(geometry: BufferGeometry, color: ColorRepresentation | undefined) { + const geo = new EdgesGeometry(geometry); + const mat = new LineBasicMaterial({ color, linewidth: 2 }); + const edge = new LineSegments(geo, mat); + return edge +} +/** 校准模型初始位置 */ +export function getCalibratedGroup(offset: Number3, ...obj3d: Object3D[]) { + const offsetGroup = new Group() + offsetGroup.add(...obj3d) + offsetGroup.children.forEach(e => e.position.set(...xyz(offset))) + return offsetGroup +} +/** 获取模型初始位置的校准偏移值 */ +export function getCalibratedOffset(thickness: number) { + return { x: 0, y: 0, z: -thickness / 2 } +} +export function paramModelRegeneration(model: IExportParamModelData) { + const { modelTypeId } = model + if (modelTypeId === 2) model = fillShapeData(model) + const { rotate, position, thickness } = model; + if (modelTypeId === 3 || modelTypeId === 2) { + const plankShape = getShapeFromModel(model) + // 板件材质设置 + const plank = getPlank(plankShape, thickness) + // 板件描边 + const plankEdge = getEdge(plank.geometry, 'black') + // 板件模型初始位置校准 + const offset = getCalibratedOffset(thickness) + const calibratedGroup = getCalibratedGroup(offset, plank, plankEdge) + calibratedGroup.setRotationFromEuler(new Euler(...xyz(rotate!), 'ZYX')) + // 板件位置还原 + calibratedGroup.position.set(...xyz(position!)) + return calibratedGroup + } +} +/** 使用绝对位置,还原元件形状与位置 */ +export function addShapeAbsolute(model: IExportParamModelData) { + const floorModel = getFloorModels(model) + const shapes = floorModel.map(model => { + const { absPosition: position, absRotation: rotate } = model + return paramModelRegeneration({ ...model, position, rotate })! + } + ) + return new Group().add(...shapes) +} +/** 使用相对位置,还原元件形状与位置 */ +export function addShapeRelative(model: IExportParamModelData) { + const { scale, rotate, position } = model; + const group = new Group() + group.position.set(...xyz(position!)) + group.rotation.set(...xyz(rotate!)) + group.scale.set(...xyz(scale)) + const shapes = model.subModels.map(model => + paramModelRegeneration(model) || addShapeRelative(model) + ) + group.add(...shapes) + return group +} \ No newline at end of file diff --git a/src/utils/service.ts b/src/utils/service.ts index 04739cf..5f598c9 100644 --- a/src/utils/service.ts +++ b/src/utils/service.ts @@ -1,6 +1,5 @@ import type { IExportParamModelData } from "@manycore/custom-miniapp-sdk"; -import { getFloorModels, listenIdpMsgOnce } from "./helper"; -import { IThreeData } from "./type"; +import { listenIdpMsgOnce } from "./helper"; /** 获取导出的方案数据 */ async function getExportJson() { @@ -13,57 +12,4 @@ export async function getParamModels() { const json = await getExportJson(); const paramModels: IExportParamModelData[] = json?.data?.paramModel; return paramModels || []; -} - -/** 获取边框形状 */ -function getShapeFormBox(model: IExportParamModelData) { - const { size } = model; - const center = { x: 0, y: 0, z: 0 } - const points = [ - { x: center.x - size.x / 2, y: center.y - size.y / 2 }, - { x: center.x - size.x / 2, y: center.y + size.y / 2 }, - { x: center.x + size.x / 2, y: center.y + size.y / 2 }, - { x: center.x + size.x / 2, y: center.y - size.y / 2 }, - ]; - const thickness = size.z; - return { points, thickness }; -} - -/** 获取THREE所需数据 */ -export async function getThreeDatas() { - const paramModels = await getParamModels(); - return paramModels.map(async (paramModel) => { - const floorModels = getFloorModels(paramModel); - - // 五金件 - const hardwareModels = floorModels.filter( - (model) => model.modelTypeId === 2 - ); - // console.log(hardwareModels); - const hardware = hardwareModels.map((model) => { - const position = model.absPosition; - const rotate = model.absRotation; - const shape = getShapeFormBox(model); - return { position, rotate, lines: new Array(shape.points.length).fill({}), holesPoints: [], holesLines: [], ...shape }; - }); - - // 元件 - const elementModels = floorModels.filter((model) => model.modelTypeId === 3) - // console.log(elementModels); - const element = elementModels.filter(subModel => subModel.paramPlankPath).map((subModel) => { - const position = subModel.absPosition; - const rotate = subModel.absRotation; - // @ts-ignore - const points = subModel.paramPlankPath.path?.resultPoints; - const thickness = subModel.thickness; - // @ts-ignore - const lines = subModel.paramPlankPath.path?.resultLines; - // @ts-ignore - const holesPoints = subModel.paramPlankPath.holes.map((e) => e.resultPoints); - // @ts-ignore - const holesLines = subModel.paramPlankPath.holes.map((e) => e.resultLines); - return { position, rotate, points, lines, thickness, holesPoints, holesLines }; - }); - return [...element, ...hardware]; - }); -} +} \ No newline at end of file diff --git a/src/views/JsonTo3d.vue b/src/views/JsonTo3d.vue index 0073357..312a29d 100644 --- a/src/views/JsonTo3d.vue +++ b/src/views/JsonTo3d.vue @@ -1,13 +1,11 @@