|
@@ -1,26 +1,29 @@
|
|
|
<template></template>
|
|
|
|
|
|
<script lang="ts" setup>
|
|
|
-import { getLineIconMat, getSnapLine, LineIconData } from "@/core/components/line-icon";
|
|
|
+import {
|
|
|
+ getLineIconEndpoints,
|
|
|
+ getSnapLine,
|
|
|
+ LineIconData,
|
|
|
+} from "@/core/components/line-icon";
|
|
|
import { useRender, useStageProps, useTree } from "../../hook/use-stage";
|
|
|
-import { getModel } from "./resource";
|
|
|
-import { Box3, MathUtils, Matrix4, Object3D, Vector3 } from "three";
|
|
|
-import { computed, ref, watch } from "vue";
|
|
|
+import { fullMesh, getModel } from "./resource";
|
|
|
+import { Group, Matrix4 } from "three";
|
|
|
+import { computed, ref, watch, watchEffect } from "vue";
|
|
|
+import { lineCenter, lineVector, vector2IncludedAngle } from "@/utils/math";
|
|
|
+import { setMat } from "../../util";
|
|
|
|
|
|
const props = defineProps<{ data: LineIconData }>();
|
|
|
const render = useRender();
|
|
|
-const group = new Object3D();
|
|
|
-const model = ref<Object3D>();
|
|
|
+
|
|
|
+const group = new Group();
|
|
|
watch(
|
|
|
() => props.data.url,
|
|
|
async (type, _, onCleanup) => {
|
|
|
let typeModel = await getModel(type);
|
|
|
if (typeModel && type === props.data.url) {
|
|
|
typeModel = typeModel.clone();
|
|
|
- model.value = typeModel;
|
|
|
group.add(typeModel);
|
|
|
- const box3 = new Box3();
|
|
|
- box3.setFromObject(group);
|
|
|
render();
|
|
|
onCleanup(() => {
|
|
|
group.remove(typeModel!);
|
|
@@ -35,39 +38,72 @@ const store = useStageProps().value.draw.store;
|
|
|
const line = computed(
|
|
|
() => store.getTypeItems("line")[0].lines.find((item) => item.id === props.data.lineId)!
|
|
|
);
|
|
|
+const fullHeight = ["men_l", "yimen", "shuangkaimen", "luodichuang"];
|
|
|
+const fullThickness = ["men_l", "yimen", "shuangkaimen", "luodichuang"];
|
|
|
|
|
|
-const config = computed(() => {
|
|
|
- const fullTypes = ["men_l", "piaochuang"];
|
|
|
- const data = { ...props.data };
|
|
|
- if (fullTypes.some((t) => data.url.includes(t))) {
|
|
|
- data.type = "full";
|
|
|
- }
|
|
|
- const config = getLineIconMat(getSnapLine(store, data)!, data).decompose();
|
|
|
- return config;
|
|
|
+const height = computed(() => {
|
|
|
+ const isFullHeight = fullHeight.some((t) => props.data.url.includes(t));
|
|
|
+ return isFullHeight ? sProps.value.height : sProps.value.height / 2;
|
|
|
+});
|
|
|
+const bottom = computed(
|
|
|
+ () => height.value / 2 + (sProps.value.height - height.value) / 2
|
|
|
+);
|
|
|
+const thickness = computed(() => {
|
|
|
+ const isFullThickness = fullThickness.some((t) => props.data.url.includes(t));
|
|
|
+ return isFullThickness ? line.value.strokeWidth : props.data.height;
|
|
|
});
|
|
|
-const width = computed(() => Math.abs(props.data.endLen - props.data.startLen));
|
|
|
const sProps = useStageProps();
|
|
|
-
|
|
|
const mat = computed(() => {
|
|
|
- return new Matrix4()
|
|
|
- .makeTranslation(new Vector3(config.value.x, sProps.value.height / 2, config.value.y))
|
|
|
- .multiply(new Matrix4().makeRotationY(MathUtils.degToRad(config.value.rotation)))
|
|
|
- .multiply(
|
|
|
- new Matrix4().makeScale(
|
|
|
- width.value * config.value.scaleX,
|
|
|
- sProps.value.height,
|
|
|
- line.value.strokeWidth * config.value.scaleY
|
|
|
- )
|
|
|
- );
|
|
|
+ const data = props.data;
|
|
|
+ const snapLine = getSnapLine(store, data)!;
|
|
|
+ const points = getLineIconEndpoints(snapLine, data);
|
|
|
+ const lineRotate = vector2IncludedAngle(lineVector(points), { x: 1, y: 0 });
|
|
|
+ const center = lineCenter(points);
|
|
|
+
|
|
|
+ const width = Math.abs(props.data.endLen - props.data.startLen);
|
|
|
+ const mat = new Matrix4()
|
|
|
+ .makeTranslation(center.x, bottom.value, center.y)
|
|
|
+ .multiply(new Matrix4().makeRotationY(lineRotate));
|
|
|
+
|
|
|
+ if (props.data.openSide === "RIGHT") {
|
|
|
+ mat.multiply(new Matrix4().makeScale(1, 1, -1));
|
|
|
+ }
|
|
|
+ if (line.value.strokeWidth !== thickness.value) {
|
|
|
+ const outer = -thickness.value / 2 + line.value.strokeWidth / 2;
|
|
|
+ mat.multiply(new Matrix4().makeTranslation(0, 0, outer));
|
|
|
+ }
|
|
|
+
|
|
|
+ mat.multiply(new Matrix4().makeScale(width, height.value, thickness.value));
|
|
|
+ return mat;
|
|
|
+});
|
|
|
+
|
|
|
+watchEffect((onCleanup) => {
|
|
|
+ if (height.value === sProps.value.height) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ const scale = bottom.value / sProps.value.height;
|
|
|
+ const topMesh = fullMesh.clone();
|
|
|
+ topMesh.scale.set(1, scale, 1);
|
|
|
+ topMesh.position.add({ x: 0, y: 0.75, z: 0 });
|
|
|
+
|
|
|
+ const bottomMesh = fullMesh.clone();
|
|
|
+ bottomMesh.scale.set(1, scale, 1);
|
|
|
+ bottomMesh.position.add({ x: 0, y: -0.75, z: 0 });
|
|
|
+
|
|
|
+ group.add(topMesh);
|
|
|
+ group.add(bottomMesh);
|
|
|
+ render();
|
|
|
+ onCleanup(() => {
|
|
|
+ group.remove(topMesh);
|
|
|
+ group.remove(bottomMesh);
|
|
|
+ render();
|
|
|
+ });
|
|
|
});
|
|
|
|
|
|
watch(
|
|
|
mat,
|
|
|
(mat) => {
|
|
|
- group.matrixAutoUpdate = false;
|
|
|
- group.matrix.copy(mat);
|
|
|
- group.matrixWorldNeedsUpdate = true;
|
|
|
-
|
|
|
+ setMat(group, mat);
|
|
|
render();
|
|
|
},
|
|
|
{ immediate: true }
|