From 3abd6d96415949c7da84af464a3cc1a3f2ed0b20 Mon Sep 17 00:00:00 2001 From: brokenstring314 <15635128186@163.com> Date: Thu, 8 May 2025 12:03:01 +0800 Subject: [PATCH 1/2] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20=E4=BC=98=E5=8C=96?= =?UTF-8?q?=E4=BB=A3=E7=A0=81=E7=BB=93=E6=9E=84=20-=20=E6=94=B9=E5=8F=98St?= =?UTF-8?q?ageNodeRotate=E3=80=81StageNodeAdder=E7=9A=84=E5=BC=80=E5=A4=B4?= =?UTF-8?q?=E5=A4=A7=E5=B0=8F=E5=86=99=20-=20Cublic=20=E6=94=B9=E4=B8=BA?= =?UTF-8?q?=20Cubic=20=EF=BC=88CR=E6=9B=B2=E7=BA=BF=EF=BC=89=20-=20?= =?UTF-8?q?=E4=BC=98=E5=8C=96=20StageDeleteManager=20=E5=92=8C=20deleteEnt?= =?UTF-8?q?ities=E5=87=BD=E6=95=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...omSpline.tsx => CubicCatmullRomSpline.tsx} | 2 +- .../entityRenderer/CollisionBoxRenderer.tsx | 6 +- .../entityRenderer/edge/EdgeRenderer.tsx | 6 +- app/src/core/render/canvas2d/renderer.tsx | 4 +- .../utilsRenderer/WorldRenderUtils.tsx | 4 +- .../controller/ControllerClass.tsx | 21 +- .../concrete/ControllerAssociationReshape.tsx | 2 +- .../concrete/ControllerEntityCreate.tsx | 2 +- .../concrete/ControllerNodeConnection.tsx | 2 +- .../controller/concrete/utilsControl.tsx | 4 +- .../keyboardOnlyGraphEngine.tsx | 2 +- .../secretKeysEngine/secretKeysEngine.tsx | 4 +- .../service/dataFileService/fileLoader.tsx | 6 +- app/src/core/stage/StageDumper.tsx | 10 +- .../core/stage/stageManager/StageManager.tsx | 16 +- .../concreteMethods/StageDeleteManager.tsx | 45 +- .../concreteMethods/StageNodeAdder.tsx | 398 ++++++++++++++++++ .../concreteMethods/StageNodeConnector.tsx | 4 +- .../concreteMethods/StageNodeRotate.tsx | 117 +++++ .../StageObjectSelectCounter.tsx | 4 +- .../concreteMethods/StageSerializedAdder.tsx | 6 +- ...Edge.tsx => CubicCatmullRomSplineEdge.tsx} | 22 +- app/src/types/node.tsx | 10 +- 23 files changed, 612 insertions(+), 85 deletions(-) rename app/src/core/dataStruct/shape/{CublicCatmullRomSpline.tsx => CubicCatmullRomSpline.tsx} (98%) create mode 100644 app/src/core/stage/stageManager/concreteMethods/StageNodeAdder.tsx create mode 100644 app/src/core/stage/stageManager/concreteMethods/StageNodeRotate.tsx rename app/src/core/stage/stageObject/association/{CublicCatmullRomSplineEdge.tsx => CubicCatmullRomSplineEdge.tsx} (85%) diff --git a/app/src/core/dataStruct/shape/CublicCatmullRomSpline.tsx b/app/src/core/dataStruct/shape/CubicCatmullRomSpline.tsx similarity index 98% rename from app/src/core/dataStruct/shape/CublicCatmullRomSpline.tsx rename to app/src/core/dataStruct/shape/CubicCatmullRomSpline.tsx index faad3182..c22f4857 100644 --- a/app/src/core/dataStruct/shape/CublicCatmullRomSpline.tsx +++ b/app/src/core/dataStruct/shape/CubicCatmullRomSpline.tsx @@ -7,7 +7,7 @@ import { Shape } from "./Shape"; /** * CR曲线形状 */ -export class CublicCatmullRomSpline extends Shape { +export class CubicCatmullRomSpline extends Shape { public controlPoints: Vector[]; public alpha: number; public tension: number; diff --git a/app/src/core/render/canvas2d/entityRenderer/CollisionBoxRenderer.tsx b/app/src/core/render/canvas2d/entityRenderer/CollisionBoxRenderer.tsx index a9c83939..9deda26a 100644 --- a/app/src/core/render/canvas2d/entityRenderer/CollisionBoxRenderer.tsx +++ b/app/src/core/render/canvas2d/entityRenderer/CollisionBoxRenderer.tsx @@ -1,6 +1,6 @@ import { Color } from "../../../dataStruct/Color"; import { Circle } from "../../../dataStruct/shape/Circle"; -import { CublicCatmullRomSpline } from "../../../dataStruct/shape/CublicCatmullRomSpline"; +import { CubicCatmullRomSpline } from "../../../dataStruct/shape/CubicCatmullRomSpline"; import { SymmetryCurve } from "../../../dataStruct/shape/Curve"; import { Line } from "../../../dataStruct/shape/Line"; import { Rectangle } from "../../../dataStruct/shape/Rectangle"; @@ -50,8 +50,8 @@ export namespace CollisionBoxRenderer { // const size = 15; // 箭头大小 // shape.end = shape.end.subtract(shape.endDirection.multiply(size / -2)); WorldRenderUtils.renderSymmetryCurve(shape, color, 10); - } else if (shape instanceof CublicCatmullRomSpline) { - WorldRenderUtils.renderCublicCatmullRomSpline(shape, color, 10); + } else if (shape instanceof CubicCatmullRomSpline) { + WorldRenderUtils.renderCubicCatmullRomSpline(shape, color, 10); } } } diff --git a/app/src/core/render/canvas2d/entityRenderer/edge/EdgeRenderer.tsx b/app/src/core/render/canvas2d/entityRenderer/edge/EdgeRenderer.tsx index 8649c380..4776e4d9 100644 --- a/app/src/core/render/canvas2d/entityRenderer/edge/EdgeRenderer.tsx +++ b/app/src/core/render/canvas2d/entityRenderer/edge/EdgeRenderer.tsx @@ -3,7 +3,7 @@ import { Color } from "../../../../dataStruct/Color"; import { Vector } from "../../../../dataStruct/Vector"; import { Settings } from "../../../../service/Settings"; import { Camera } from "../../../../stage/Camera"; -import { CublicCatmullRomSplineEdge } from "../../../../stage/stageObject/association/CublicCatmullRomSplineEdge"; +import { CubicCatmullRomSplineEdge } from "../../../../stage/stageObject/association/CubicCatmullRomSplineEdge"; import { LineEdge } from "../../../../stage/stageObject/association/LineEdge"; import { Section } from "../../../../stage/stageObject/entity/Section"; @@ -106,14 +106,14 @@ export namespace EdgeRenderer { } } - export function renderCrEdge(edge: CublicCatmullRomSplineEdge) { + export function renderCrEdge(edge: CubicCatmullRomSplineEdge) { if (edge.source.isHiddenBySectionCollapse && edge.target.isHiddenBySectionCollapse) { return; } const crShape = edge.getShape(); const edgeColor = edge.color.a === 0 ? StageStyleManager.currentStyle.StageObjectBorder : edge.color; // 画曲线 - WorldRenderUtils.renderCublicCatmullRomSpline(crShape, edgeColor, 2); + WorldRenderUtils.renderCubicCatmullRomSpline(crShape, edgeColor, 2); if (edge.isSelected) { CollisionBoxRenderer.render(edge.collisionBox, StageStyleManager.currentStyle.CollideBoxSelected); } diff --git a/app/src/core/render/canvas2d/renderer.tsx b/app/src/core/render/canvas2d/renderer.tsx index c8ca84ee..133ab106 100644 --- a/app/src/core/render/canvas2d/renderer.tsx +++ b/app/src/core/render/canvas2d/renderer.tsx @@ -18,7 +18,7 @@ import { StageHistoryManager } from "../../stage/stageManager/StageHistoryManage import { StageManager } from "../../stage/stageManager/StageManager"; import { StageObjectSelectCounter } from "../../stage/stageManager/concreteMethods/StageObjectSelectCounter"; import { StageObject } from "../../stage/stageObject/abstract/StageObject"; -import { CublicCatmullRomSplineEdge } from "../../stage/stageObject/association/CublicCatmullRomSplineEdge"; +import { CubicCatmullRomSplineEdge } from "../../stage/stageObject/association/CubicCatmullRomSplineEdge"; import { LineEdge } from "../../stage/stageObject/association/LineEdge"; import { MultiTargetUndirectedEdge } from "../../stage/stageObject/association/MutiTargetUndirectedEdge"; import { CurveRenderer } from "./basicRenderer/curveRenderer"; @@ -635,7 +635,7 @@ export namespace Renderer { if (association instanceof LineEdge) { EdgeRenderer.renderLineEdge(association); } - if (association instanceof CublicCatmullRomSplineEdge) { + if (association instanceof CubicCatmullRomSplineEdge) { EdgeRenderer.renderCrEdge(association); } renderedEdges++; diff --git a/app/src/core/render/canvas2d/utilsRenderer/WorldRenderUtils.tsx b/app/src/core/render/canvas2d/utilsRenderer/WorldRenderUtils.tsx index 2534c70b..422e7a64 100644 --- a/app/src/core/render/canvas2d/utilsRenderer/WorldRenderUtils.tsx +++ b/app/src/core/render/canvas2d/utilsRenderer/WorldRenderUtils.tsx @@ -1,5 +1,5 @@ import { Color } from "../../../dataStruct/Color"; -import { CublicCatmullRomSpline } from "../../../dataStruct/shape/CublicCatmullRomSpline"; +import { CubicCatmullRomSpline } from "../../../dataStruct/shape/CubicCatmullRomSpline"; import { CubicBezierCurve, SymmetryCurve } from "../../../dataStruct/shape/Curve"; import { Rectangle } from "../../../dataStruct/shape/Rectangle"; import { Vector } from "../../../dataStruct/Vector"; @@ -19,7 +19,7 @@ export namespace WorldRenderUtils { * 绘制一条Catmull-Rom样条线 * @param curve */ - export function renderCublicCatmullRomSpline(spline: CublicCatmullRomSpline, color: Color, width: number): void { + export function renderCubicCatmullRomSpline(spline: CubicCatmullRomSpline, color: Color, width: number): void { const points = spline.computePath().map(Renderer.transformWorld2View); width *= Camera.currentScale; const start = Renderer.transformWorld2View(spline.controlPoints[1]); diff --git a/app/src/core/service/controlService/controller/ControllerClass.tsx b/app/src/core/service/controlService/controller/ControllerClass.tsx index ae692648..e092182f 100644 --- a/app/src/core/service/controlService/controller/ControllerClass.tsx +++ b/app/src/core/service/controlService/controller/ControllerClass.tsx @@ -105,9 +105,10 @@ export class ControllerClass { private _touchstart = (event: TouchEvent) => { event.preventDefault(); - const touch = event.touches[event.touches.length - 1] as any as MouseEvent; - // @ts-expect-error 必须给他来一个button属性 - touch.button = 0; + const touch = { + ...(event.touches[event.touches.length - 1] as unknown as MouseEvent), + button: 0, // 通过对象展开实现相对安全的属性合并 + } as MouseEvent; if (event.touches.length > 1) { Stage.selectMachine.shutDown(); } @@ -116,17 +117,19 @@ export class ControllerClass { private _touchmove = (event: TouchEvent) => { event.preventDefault(); - const touch = event.touches[event.touches.length - 1] as any as MouseEvent; - // @ts-expect-error 必须给他来一个button属性 - touch.button = 0; + const touch = { + ...(event.touches[event.touches.length - 1] as unknown as MouseEvent), + button: 0, // 通过对象展开实现相对安全的属性合并 + } as MouseEvent; this.mousemove(touch); }; private _touchend = (event: TouchEvent) => { event.preventDefault(); - const touch = event.changedTouches[event.changedTouches.length - 1] as any as MouseEvent; - // @ts-expect-error 必须给他来一个button属性 - touch.button = 0; + const touch = { + ...(event.touches[event.touches.length - 1] as unknown as MouseEvent), + button: 0, // 通过对象展开实现相对安全的属性合并 + } as MouseEvent; this._mouseup(touch); }; diff --git a/app/src/core/service/controlService/controller/concrete/ControllerAssociationReshape.tsx b/app/src/core/service/controlService/controller/concrete/ControllerAssociationReshape.tsx index 051794a9..d78dc99b 100644 --- a/app/src/core/service/controlService/controller/concrete/ControllerAssociationReshape.tsx +++ b/app/src/core/service/controlService/controller/concrete/ControllerAssociationReshape.tsx @@ -4,7 +4,7 @@ import { Renderer } from "../../../../render/canvas2d/renderer"; import { LeftMouseModeEnum, Stage } from "../../../../stage/Stage"; import { StageMultiTargetEdgeMove } from "../../../../stage/stageManager/concreteMethods/StageMultiTargetEdgeMove"; import { StageNodeConnector } from "../../../../stage/stageManager/concreteMethods/StageNodeConnector"; -import { StageNodeRotate } from "../../../../stage/stageManager/concreteMethods/stageNodeRotate"; +import { StageNodeRotate } from "../../../../stage/stageManager/concreteMethods/StageNodeRotate"; import { StageHistoryManager } from "../../../../stage/stageManager/StageHistoryManager"; import { StageManager } from "../../../../stage/stageManager/StageManager"; import { MultiTargetUndirectedEdge } from "../../../../stage/stageObject/association/MutiTargetUndirectedEdge"; diff --git a/app/src/core/service/controlService/controller/concrete/ControllerEntityCreate.tsx b/app/src/core/service/controlService/controller/concrete/ControllerEntityCreate.tsx index e1d2cbb7..35c623b2 100644 --- a/app/src/core/service/controlService/controller/concrete/ControllerEntityCreate.tsx +++ b/app/src/core/service/controlService/controller/concrete/ControllerEntityCreate.tsx @@ -2,7 +2,7 @@ import { Vector } from "../../../../dataStruct/Vector"; import { Renderer } from "../../../../render/canvas2d/renderer"; import { LeftMouseModeEnum, Stage } from "../../../../stage/Stage"; import { SectionMethods } from "../../../../stage/stageManager/basicMethods/SectionMethods"; -import { StageNodeAdder } from "../../../../stage/stageManager/concreteMethods/stageNodeAdder"; +import { StageNodeAdder } from "../../../../stage/stageManager/concreteMethods/StageNodeAdder"; import { StageObjectSelectCounter } from "../../../../stage/stageManager/concreteMethods/StageObjectSelectCounter"; import { StageManager } from "../../../../stage/stageManager/StageManager"; import { Section } from "../../../../stage/stageObject/entity/Section"; diff --git a/app/src/core/service/controlService/controller/concrete/ControllerNodeConnection.tsx b/app/src/core/service/controlService/controller/concrete/ControllerNodeConnection.tsx index 578aa53b..e4f5d3c7 100644 --- a/app/src/core/service/controlService/controller/concrete/ControllerNodeConnection.tsx +++ b/app/src/core/service/controlService/controller/concrete/ControllerNodeConnection.tsx @@ -14,7 +14,7 @@ import { ControllerClass } from "../ControllerClass"; import { addTextNodeByLocation } from "./utilsControl"; import { StageStyleManager } from "../../../feedbackService/stageStyle/StageStyleManager"; import { SectionMethods } from "../../../../stage/stageManager/basicMethods/SectionMethods"; -import { StageNodeAdder } from "../../../../stage/stageManager/concreteMethods/stageNodeAdder"; +import { StageNodeAdder } from "../../../../stage/stageManager/concreteMethods/StageNodeAdder"; import { Line } from "../../../../dataStruct/shape/Line"; import { Direction } from "../../../../../types/directions"; diff --git a/app/src/core/service/controlService/controller/concrete/utilsControl.tsx b/app/src/core/service/controlService/controller/concrete/utilsControl.tsx index c8a255a7..d16afb78 100644 --- a/app/src/core/service/controlService/controller/concrete/utilsControl.tsx +++ b/app/src/core/service/controlService/controller/concrete/utilsControl.tsx @@ -7,7 +7,7 @@ import { InputElement } from "../../../../render/domElement/inputElement"; import { Camera } from "../../../../stage/Camera"; import { Stage } from "../../../../stage/Stage"; import { SectionMethods } from "../../../../stage/stageManager/basicMethods/SectionMethods"; -import { StageNodeAdder } from "../../../../stage/stageManager/concreteMethods/stageNodeAdder"; +import { StageNodeAdder } from "../../../../stage/stageManager/concreteMethods/StageNodeAdder"; import { StageObjectSelectCounter } from "../../../../stage/stageManager/concreteMethods/StageObjectSelectCounter"; import { StageHistoryManager } from "../../../../stage/stageManager/StageHistoryManager"; import { StageManager } from "../../../../stage/stageManager/StageManager"; @@ -126,6 +126,7 @@ export function editEdgeText(clickedLineEdge: Edge, selectAll = true) { selectAll, ).then(() => { // clickedLineEdge!.isEditing = false; + // 因为这里用的是不透明文本框,所以不需要停止节点上文字的渲染 Controller.isCameraLocked = false; StageHistoryManager.recordStep(); }); @@ -160,6 +161,7 @@ export function editMultiTargetEdgeText(clickedEdge: MultiTargetUndirectedEdge, selectAll, ).then(() => { // clickedLineEdge!.isEditing = false; + // 因为这里用的是不透明文本框,所以不需要停止节点上文字的渲染 Controller.isCameraLocked = false; StageHistoryManager.recordStep(); }); diff --git a/app/src/core/service/controlService/keyboardOnlyEngine/keyboardOnlyGraphEngine.tsx b/app/src/core/service/controlService/keyboardOnlyEngine/keyboardOnlyGraphEngine.tsx index f4320378..3d72845a 100644 --- a/app/src/core/service/controlService/keyboardOnlyEngine/keyboardOnlyGraphEngine.tsx +++ b/app/src/core/service/controlService/keyboardOnlyEngine/keyboardOnlyGraphEngine.tsx @@ -2,7 +2,7 @@ import { Vector } from "../../../dataStruct/Vector"; import { EdgeRenderer } from "../../../render/canvas2d/entityRenderer/edge/EdgeRenderer"; // import { Camera } from "../../../stage/Camera"; import { Stage } from "../../../stage/Stage"; -import { StageNodeAdder } from "../../../stage/stageManager/concreteMethods/stageNodeAdder"; +import { StageNodeAdder } from "../../../stage/stageManager/concreteMethods/StageNodeAdder"; import { StageManager } from "../../../stage/stageManager/StageManager"; import { ConnectableEntity } from "../../../stage/stageObject/abstract/ConnectableEntity"; import { TextRiseEffect } from "../../feedbackService/effectEngine/concrete/TextRiseEffect"; diff --git a/app/src/core/service/controlService/secretKeysEngine/secretKeysEngine.tsx b/app/src/core/service/controlService/secretKeysEngine/secretKeysEngine.tsx index eee6224d..5a58005f 100644 --- a/app/src/core/service/controlService/secretKeysEngine/secretKeysEngine.tsx +++ b/app/src/core/service/controlService/secretKeysEngine/secretKeysEngine.tsx @@ -13,7 +13,7 @@ import { StageManager } from "../../../stage/stageManager/StageManager"; import { SectionMethods } from "../../../stage/stageManager/basicMethods/SectionMethods"; import { LayoutManualAlignManager } from "../../../stage/stageManager/concreteMethods/layoutManager/layoutManualAlignManager"; import { ConnectableEntity } from "../../../stage/stageObject/abstract/ConnectableEntity"; -import { CublicCatmullRomSplineEdge } from "../../../stage/stageObject/association/CublicCatmullRomSplineEdge"; +import { CubicCatmullRomSplineEdge } from "../../../stage/stageObject/association/CubicCatmullRomSplineEdge"; import { LineEdge } from "../../../stage/stageObject/association/LineEdge"; import { PortalNode } from "../../../stage/stageObject/entity/PortalNode"; import { Section } from "../../../stage/stageObject/entity/Section"; @@ -626,7 +626,7 @@ export class SecretKeysEngine { isHidden: true, func() { const selectedCREdge = StageManager.getSelectedAssociations().filter( - (edge) => edge instanceof CublicCatmullRomSplineEdge, + (edge) => edge instanceof CubicCatmullRomSplineEdge, ); for (const edge of selectedCREdge) { edge.addControlPoint(); diff --git a/app/src/core/service/dataFileService/fileLoader.tsx b/app/src/core/service/dataFileService/fileLoader.tsx index 67d6b849..2f9f5fd5 100644 --- a/app/src/core/service/dataFileService/fileLoader.tsx +++ b/app/src/core/service/dataFileService/fileLoader.tsx @@ -15,7 +15,7 @@ import { PortalNode } from "../../stage/stageObject/entity/PortalNode"; import { PathString } from "../../../utils/pathString"; import { isWeb } from "../../../utils/platform"; import { Vector } from "../../dataStruct/Vector"; -import { CublicCatmullRomSplineEdge } from "../../stage/stageObject/association/CublicCatmullRomSplineEdge"; +import { CubicCatmullRomSplineEdge } from "../../stage/stageObject/association/CubicCatmullRomSplineEdge"; import { MultiTargetUndirectedEdge } from "../../stage/stageObject/association/MutiTargetUndirectedEdge"; import { RecentFileManager } from "./RecentFileManager"; import { SvgNode } from "../../stage/stageObject/entity/SvgNode"; @@ -169,8 +169,8 @@ export namespace FileLoader { let newAssociation = null; if (Serialized.isLineEdge(edge)) { newAssociation = new LineEdge(edge); - } else if (Serialized.isCublicCatmullRomSplineEdge(edge)) { - newAssociation = new CublicCatmullRomSplineEdge(edge); + } else if (Serialized.isCubicCatmullRomSplineEdge(edge)) { + newAssociation = new CubicCatmullRomSplineEdge(edge); } else if (Serialized.isMultiTargetUndirectedEdge(edge)) { newAssociation = new MultiTargetUndirectedEdge(edge); } diff --git a/app/src/core/stage/StageDumper.tsx b/app/src/core/stage/StageDumper.tsx index 29b25cce..c136940c 100644 --- a/app/src/core/stage/StageDumper.tsx +++ b/app/src/core/stage/StageDumper.tsx @@ -3,7 +3,7 @@ import { SectionMethods } from "./stageManager/basicMethods/SectionMethods"; import { StageManager } from "./stageManager/StageManager"; import { Association } from "./stageObject/abstract/Association"; import { Entity } from "./stageObject/abstract/StageEntity"; -import { CublicCatmullRomSplineEdge } from "./stageObject/association/CublicCatmullRomSplineEdge"; +import { CubicCatmullRomSplineEdge } from "./stageObject/association/CubicCatmullRomSplineEdge"; import { LineEdge } from "./stageObject/association/LineEdge"; import { MultiTargetUndirectedEdge } from "./stageObject/association/MutiTargetUndirectedEdge"; import { ConnectPoint } from "./stageObject/entity/ConnectPoint"; @@ -49,13 +49,13 @@ export namespace StageDumper { targetRectRate: [edge.targetRectangleRate.x, edge.targetRectangleRate.y], }; } - export function dumpCrEdge(edge: CublicCatmullRomSplineEdge): Serialized.CublicCatmullRomSplineEdge { + export function dumpCrEdge(edge: CubicCatmullRomSplineEdge): Serialized.CubicCatmullRomSplineEdge { return { source: edge.source.uuid, target: edge.target.uuid, text: edge.text, uuid: edge.uuid, - type: "core:cublic_catmull_rom_spline_edge", + type: "core:cubic_catmull_rom_spline_edge", controlPoints: edge.getControlPoints().map((point) => [point.x, point.y]), alpha: edge.alpha, tension: edge.tension, @@ -193,7 +193,7 @@ export namespace StageDumper { export function dumpOneAssociation(association: Association): Serialized.CoreAssociation { if (association instanceof LineEdge) { return dumpEdge(association); - } else if (association instanceof CublicCatmullRomSplineEdge) { + } else if (association instanceof CubicCatmullRomSplineEdge) { return dumpCrEdge(association); } else if (association instanceof MultiTargetUndirectedEdge) { return dumpMTUEdge(association); @@ -297,7 +297,7 @@ export namespace StageDumper { if (entities.includes(edge.source) && entities.includes(edge.target)) { result.push(dumpEdge(edge)); } - } else if (edge instanceof CublicCatmullRomSplineEdge) { + } else if (edge instanceof CubicCatmullRomSplineEdge) { if (entities.includes(edge.source) && entities.includes(edge.target)) { result.push(dumpCrEdge(edge)); } diff --git a/app/src/core/stage/stageManager/StageManager.tsx b/app/src/core/stage/stageManager/StageManager.tsx index 49839f0c..6300bf23 100644 --- a/app/src/core/stage/stageManager/StageManager.tsx +++ b/app/src/core/stage/stageManager/StageManager.tsx @@ -16,7 +16,7 @@ import { Association } from "../stageObject/abstract/Association"; import { ConnectableEntity } from "../stageObject/abstract/ConnectableEntity"; import { Entity } from "../stageObject/abstract/StageEntity"; import { StageObject } from "../stageObject/abstract/StageObject"; -import { CublicCatmullRomSplineEdge } from "../stageObject/association/CublicCatmullRomSplineEdge"; +import { CubicCatmullRomSplineEdge } from "../stageObject/association/CubicCatmullRomSplineEdge"; import { Edge } from "../stageObject/association/Edge"; import { LineEdge } from "../stageObject/association/LineEdge"; import { ConnectPoint } from "../stageObject/entity/ConnectPoint"; @@ -28,7 +28,7 @@ import { TextNode } from "../stageObject/entity/TextNode"; import { UrlNode } from "../stageObject/entity/UrlNode"; import { GraphMethods } from "./basicMethods/GraphMethods"; import { StageDeleteManager } from "./concreteMethods/StageDeleteManager"; -import { StageNodeAdder } from "./concreteMethods/stageNodeAdder"; +import { StageNodeAdder } from "./concreteMethods/StageNodeAdder"; import { StageNodeConnector } from "./concreteMethods/StageNodeConnector"; import { StageObjectSelectCounter } from "./concreteMethods/StageObjectSelectCounter"; import { StageSectionInOutManager } from "./concreteMethods/StageSectionInOutManager"; @@ -284,8 +284,8 @@ export namespace StageManager { export function getLineEdges(): LineEdge[] { return stageContent.associations.valuesToArray().filter((edge) => edge instanceof LineEdge); } - export function getCrEdges(): CublicCatmullRomSplineEdge[] { - return stageContent.associations.valuesToArray().filter((edge) => edge instanceof CublicCatmullRomSplineEdge); + export function getCrEdges(): CubicCatmullRomSplineEdge[] { + return stageContent.associations.valuesToArray().filter((edge) => edge instanceof CubicCatmullRomSplineEdge); } /** 关于标签的相关操作 */ @@ -375,7 +375,7 @@ export namespace StageManager { export function addLineEdge(edge: LineEdge) { stageContent.associations.addValue(edge, edge.uuid); } - export function addCrEdge(edge: CublicCatmullRomSplineEdge) { + export function addCrEdge(edge: CubicCatmullRomSplineEdge) { stageContent.associations.addValue(edge, edge.uuid); } export function addPenStroke(penStroke: PenStroke) { @@ -1014,7 +1014,7 @@ export namespace StageManager { export function addSelectedCREdgeControlPoint() { const selectedCREdge = StageManager.getSelectedAssociations().filter( - (edge) => edge instanceof CublicCatmullRomSplineEdge, + (edge) => edge instanceof CubicCatmullRomSplineEdge, ); for (const edge of selectedCREdge) { edge.addControlPoint(); @@ -1023,7 +1023,7 @@ export namespace StageManager { export function addSelectedCREdgeTension() { const selectedCREdge = StageManager.getSelectedAssociations().filter( - (edge) => edge instanceof CublicCatmullRomSplineEdge, + (edge) => edge instanceof CubicCatmullRomSplineEdge, ); for (const edge of selectedCREdge) { edge.tension += 0.25; @@ -1033,7 +1033,7 @@ export namespace StageManager { export function reduceSelectedCREdgeTension() { const selectedCREdge = StageManager.getSelectedAssociations().filter( - (edge) => edge instanceof CublicCatmullRomSplineEdge, + (edge) => edge instanceof CubicCatmullRomSplineEdge, ); for (const edge of selectedCREdge) { edge.tension -= 0.25; diff --git a/app/src/core/stage/stageManager/concreteMethods/StageDeleteManager.tsx b/app/src/core/stage/stageManager/concreteMethods/StageDeleteManager.tsx index eaa8df3b..41af22c8 100644 --- a/app/src/core/stage/stageManager/concreteMethods/StageDeleteManager.tsx +++ b/app/src/core/stage/stageManager/concreteMethods/StageDeleteManager.tsx @@ -23,28 +23,35 @@ import { NodeLogic } from "../../../service/dataGenerateService/autoComputeEngin * 包含一切删除舞台上的元素的方法 */ export namespace StageDeleteManager { + type DeleteHandler = (entity: T) => void; + type Constructor = { new (...args: any[]): T }; + const _deleteHandlers = new Map, DeleteHandler>(); + // 类型注册器,保证一个类型对应一个函数,绝对类型安全,同时可扩展 + function registerHandler(constructor: Constructor, handler: DeleteHandler) { + _deleteHandlers.set(constructor, handler as DeleteHandler); + } + + registerHandler(TextNode, deleteTextNode); + registerHandler(Section, deleteSection); + registerHandler(ConnectPoint, deleteConnectPoint); + registerHandler(ImageNode, deleteImageNode); + registerHandler(UrlNode, deleteUrlNode); + registerHandler(PortalNode, deletePortalNode); + registerHandler(PenStroke, deletePenStroke); + registerHandler(SvgNode, deleteSvgNode); + export function deleteEntities(deleteNodes: Entity[]) { - // TODO: 这里应该优化,否则每次新加内容就得些一个类型判断 for (const entity of deleteNodes) { - if (entity instanceof TextNode) { - deleteTextNode(entity); - } else if (entity instanceof Section) { - deleteSection(entity); - } else if (entity instanceof ConnectPoint) { - deleteConnectPoint(entity); - } else if (entity instanceof ImageNode) { - deleteImageNode(entity); - } else if (entity instanceof UrlNode) { - deleteUrlNode(entity); - } else if (entity instanceof PortalNode) { - deletePortalNode(entity); - } else if (entity instanceof PenStroke) { - deletePenStroke(entity); - } else if (entity instanceof SvgNode) { - deleteSvgNode(entity); - } + const handler = findDeleteHandler(entity); + handler?.(entity); + } + } + + function findDeleteHandler(entity: Entity) { + for (const [ctor, handler] of _deleteHandlers) { + if (entity instanceof ctor) return handler; } - // StageManager.updateReferences(); + console.warn(`No delete handler for ${entity.constructor.name}`); } function deleteSvgNode(entity: SvgNode) { diff --git a/app/src/core/stage/stageManager/concreteMethods/StageNodeAdder.tsx b/app/src/core/stage/stageManager/concreteMethods/StageNodeAdder.tsx new file mode 100644 index 00000000..500f59e8 --- /dev/null +++ b/app/src/core/stage/stageManager/concreteMethods/StageNodeAdder.tsx @@ -0,0 +1,398 @@ +import { v4 as uuidv4 } from "uuid"; +import { Direction } from "../../../../types/directions"; +import { MarkdownNode, parseMarkdownToJSON } from "../../../../utils/markdownParse"; +import { Color } from "../../../dataStruct/Color"; +import { MonoStack } from "../../../dataStruct/MonoStack"; +import { ProgressNumber } from "../../../dataStruct/ProgressNumber"; +import { Vector } from "../../../dataStruct/Vector"; +import { RectanglePushInEffect } from "../../../service/feedbackService/effectEngine/concrete/RectanglePushInEffect"; +import { Settings } from "../../../service/Settings"; +import { Stage } from "../../Stage"; +import { ConnectableEntity } from "../../stageObject/abstract/ConnectableEntity"; +import { ConnectPoint } from "../../stageObject/entity/ConnectPoint"; +import { Section } from "../../stageObject/entity/Section"; +import { TextNode } from "../../stageObject/entity/TextNode"; +import { SectionMethods } from "../basicMethods/SectionMethods"; +import { StageHistoryManager } from "../StageHistoryManager"; +import { StageManager } from "../StageManager"; +import { StageManagerUtils } from "./StageManagerUtils"; +import { GraphMethods } from "../basicMethods/GraphMethods"; + +/** + * 包含增加节点的方法 + * 有可能是用鼠标增加,涉及自动命名器 + * 也有可能是用键盘增加,涉及快捷键和自动寻找空地 + */ +export namespace StageNodeAdder { + /** + * 通过点击位置增加节点 + * @param clickWorldLocation + * @returns + */ + export async function addTextNodeByClick( + clickWorldLocation: Vector, + addToSections: Section[], + selectCurrent = false, + ): Promise { + const newUUID = uuidv4(); + const node = new TextNode({ + uuid: newUUID, + text: await getAutoName(), + details: "", + location: [clickWorldLocation.x, clickWorldLocation.y], + size: [100, 100], + }); + node.color = await getAutoColor(); + // 将node本身向左上角移动,使其居中 + node.moveTo(node.rectangle.location.subtract(node.rectangle.size.divide(2))); + StageManager.addTextNode(node); + + for (const section of addToSections) { + section.children.push(node); + section.childrenUUIDs.push(node.uuid); // 修复 + section.adjustLocationAndSize(); + Stage.effectMachine.addEffect( + new RectanglePushInEffect(node.rectangle.clone(), section.rectangle.clone(), new ProgressNumber(0, 100)), + ); + } + // 处理选中问题 + if (selectCurrent) { + for (const otherNode of StageManager.getTextNodes()) { + if (otherNode.isSelected) { + otherNode.isSelected = false; + } + } + node.isSelected = true; + } + + StageHistoryManager.recordStep(); + return newUUID; + } + + /** + * 在当前已经选中的某个节点的情况下,增加节点 + * 增加在某个选中的节点的上方,下方,左方,右方等位置 + * ——快深频 + * @param selectCurrent + * @returns 返回的是创建节点的uuid,如果当前没有选中节点,则返回空字符串 + */ + export async function addTextNodeFromCurrentSelectedNode( + direction: Direction, + addToSections: Section[], + selectCurrent = false, + ): Promise { + // 先检查当前是否有选中的唯一实体 + const selectedEntities = StageManager.getSelectedEntities().filter((entity) => entity instanceof ConnectableEntity); + if (selectedEntities.length !== 1) { + // 未选中或选中多个 + return ""; + } + /** + * 当前选择的实体 + */ + const selectedEntity = selectedEntities[0]; + const entityRectangle = selectedEntity.collisionBox.getRectangle(); + let createLocation = new Vector(0, 0); + const distanceLength = 100; + if (direction === Direction.Up) { + createLocation = entityRectangle.topCenter.add(new Vector(0, -distanceLength)); + } else if (direction === Direction.Down) { + createLocation = entityRectangle.bottomCenter.add(new Vector(0, distanceLength)); + } else if (direction === Direction.Left) { + createLocation = entityRectangle.leftCenter.add(new Vector(-distanceLength, 0)); + } else if (direction === Direction.Right) { + createLocation = entityRectangle.rightCenter.add(new Vector(distanceLength, 0)); + } + addToSections = SectionMethods.getFatherSections(selectedEntity); + const uuid = await addTextNodeByClick(createLocation, addToSections, selectCurrent); + const newNode = StageManager.getTextNodeByUUID(uuid); + if (!newNode) { + throw new Error("Failed to add node"); + } + // 如果是通过上下创建的节点,则需要左对齐 + if (direction === Direction.Up || direction === Direction.Down) { + const distance = newNode.rectangle.left - entityRectangle.left; + newNode.moveTo(newNode.rectangle.location.add(new Vector(-distance, 0))); + } + if (direction === Direction.Left) { + // 顶对齐 + const distance = newNode.rectangle.top - entityRectangle.top; + newNode.moveTo(newNode.rectangle.location.add(new Vector(0, -distance))); + } + if (direction === Direction.Right) { + // 顶对齐,+ 自己对齐到目标的右侧 + const targetLocation = entityRectangle.rightTop; + newNode.moveTo(targetLocation); + } + if (direction === Direction.Up) { + const targetLocation = entityRectangle.leftTop.add(new Vector(0, newNode.collisionBox.getRectangle().height)); + newNode.moveTo(targetLocation); + } + if (direction === Direction.Down) { + const targetLocation = entityRectangle.leftBottom; + newNode.moveTo(targetLocation); + } + StageHistoryManager.recordStep(); + return uuid; + } + + async function getAutoName(): Promise { + let template = await Settings.get("autoNamerTemplate"); + template = StageManagerUtils.replaceAutoNameTemplate(template, StageManager.getTextNodes()[0]); + return template; + } + + async function getAutoColor(): Promise { + const isEnable = await Settings.get("autoFillNodeColorEnable"); + if (isEnable) { + const colorData = await Settings.get("autoFillNodeColor"); + return new Color(...colorData); + } else { + return Color.Transparent; + } + } + + export function addConnectPoint(clickWorldLocation: Vector, addToSections: Section[]): string { + const newUUID = uuidv4(); + const connectPoint = new ConnectPoint({ + uuid: newUUID, + location: [clickWorldLocation.x, clickWorldLocation.y], + }); + StageManager.addConnectPoint(connectPoint); + for (const section of addToSections) { + section.children.push(connectPoint); + section.childrenUUIDs.push(connectPoint.uuid); + section.adjustLocationAndSize(); + Stage.effectMachine.addEffect( + new RectanglePushInEffect( + connectPoint.collisionBox.getRectangle(), + section.rectangle.clone(), + new ProgressNumber(0, 100), + ), + ); + } + StageHistoryManager.recordStep(); + return newUUID; + } + /** + * 通过纯文本生成网状结构 + * + * @param text 网状结构的格式文本 + * @param diffLocation + */ + export function addNodeGraphByText(text: string, diffLocation: Vector = Vector.getZero()) { + const lines = text.split("\n"); + + if (lines.length === 0) { + return; + } + + const randomRadius = 40 * lines.length; + + const nodeDict = new Map(); + + const createNodeByName = (name: string) => { + const newUUID = uuidv4(); + const node = new TextNode({ + uuid: newUUID, + text: name, + details: "", + location: [diffLocation.x + randomRadius * Math.random(), diffLocation.y + randomRadius * Math.random()], + size: [100, 100], + }); + StageManager.addTextNode(node); + nodeDict.set(name, node); + return node; + }; + + for (const line of lines) { + if (line.trim() === "") { + continue; + } + if (line.includes("-->") || (line.includes("-") && line.includes("->"))) { + // 这一行是一个关系行 + if (line.includes("-->")) { + // 连线上无文字 + // 解析 + const names = line.split("-->"); + if (names.length !== 2) { + throw new Error(`解析时出现错误: "${line}",应该只有两个名称`); + } + const startName = names[0].trim(); + const endName = names[1].trim(); + if (startName === "" || endName === "") { + throw new Error(`解析时出现错误: "${line}",名称不能为空`); + } + let startNode = nodeDict.get(startName); + let endNode = nodeDict.get(endName); + if (!startNode) { + startNode = createNodeByName(startName); + } + if (!endNode) { + endNode = createNodeByName(endName); + } + StageManager.connectEntity(startNode, endNode); + } else { + // 连线上有文字 + // 解析 + // A -xx-> B + const names = line.split("->"); + if (names.length !== 2) { + throw new Error(`解析时出现错误: "${line}",应该只有两个名称`); + } + const leftContent = names[0].trim(); + const endName = names[1].trim(); + if (leftContent === "" || endName === "") { + throw new Error(`解析时出现错误: "${line}",名称不能为空`); + } + let endNode = nodeDict.get(endName); + if (!endNode) { + // 没有endNode,临时创建一下 + endNode = createNodeByName(endName); + } + const leftContentList = leftContent.split("-"); + if (leftContentList.length !== 2) { + throw new Error(`解析时出现错误: "${line}",左侧内容应该只有两个名称`); + } + const startName = leftContentList[0].trim(); + const edgeText = leftContentList[1].trim(); + if (startName === "" || edgeText === "") { + throw new Error(`解析时出现错误: "${line}",名称不能为空`); + } + let startNode = nodeDict.get(startName); + if (!startNode) { + // 临时创建一下 + startNode = createNodeByName(startName); + } + StageManager.connectEntity(startNode, endNode); + // 在线上填写文字 + const edge = GraphMethods.getEdgeFromTwoEntity(startNode, endNode); + if (edge === null) { + throw new Error(`解析时出现错误: "${line}",找不到对应的连线`); + } + edge.rename(edgeText); + } + } else { + // 这一行是一个节点行 + // 获取节点名称,创建节点 + const nodeName = line.trim(); + createNodeByName(nodeName); + } + } + } + /** + * 通过带有缩进格式的文本来增加节点 + */ + export function addNodeTreeByText(text: string, indention: number, diffLocation: Vector = Vector.getZero()) { + // 将本文转换成字符串数组,按换行符分割 + const lines = text.split("\n"); + + const rootUUID = uuidv4(); + + // 准备好栈和根节点 + const rootNode = new TextNode({ + uuid: rootUUID, + text: "root", + details: "", + location: [diffLocation.x, diffLocation.y], + size: [100, 100], + }); + const nodeStack = new MonoStack(); + nodeStack.push(rootNode, -1); + StageManager.addTextNode(rootNode); + // 遍历每一行 + for (let yIndex = 0; yIndex < lines.length; yIndex++) { + const line = lines[yIndex]; + // 跳过空行 + if (line.trim() === "") { + continue; + } + // 解析缩进格式 + const indent = getIndentLevel(line, indention); + // 解析文本内容 + const textContent = line.trim(); + + const newUUID = uuidv4(); + const node = new TextNode({ + uuid: newUUID, + text: textContent, + details: "", + location: [indent * 50 + diffLocation.x, yIndex * 100 + diffLocation.y], + size: [100, 100], + }); + StageManager.addTextNode(node); + + // 检查栈 + // 保持一个严格单调栈 + if (nodeStack.peek()) { + nodeStack.push(node, indent); + const fatherNode = nodeStack.unsafeGet(nodeStack.length - 2); + StageManager.connectEntity(fatherNode, node); + } + } + } + + /*** + * 'a' -> 0 + * ' a' -> 1 + * '\t\ta' -> 2 + */ + function getIndentLevel(line: string, indention: number): number { + let indent = 0; + for (let i = 0; i < line.length; i++) { + if (line[i] === " ") { + indent++; + } else if (line[i] === "\t") { + indent += indention; + } else { + break; + } + } + return Math.floor(indent / indention); + } + + export function addNodeByMarkdown(markdownText: string, diffLocation: Vector = Vector.getZero()) { + const markdownJson = parseMarkdownToJSON(markdownText); + // 遍历markdownJson + const dfsMarkdownNode = (markdownNode: MarkdownNode, deepLevel: number) => { + // visit + visitFunction(markdownNode, deepLevel); + // visited + for (const child of markdownNode.children) { + dfsMarkdownNode(child, deepLevel + 1); + } + }; + const monoStack = new MonoStack(); + monoStack.push( + new TextNode({ + uuid: uuidv4(), + text: "root", + details: "", + location: [diffLocation.x, diffLocation.y], + size: [100, 100], + }), + -1, + ); + + let visitedCount = 0; + + const visitFunction = (markdownNode: MarkdownNode, deepLevel: number) => { + visitedCount++; + const newUUID = uuidv4(); + const node = new TextNode({ + uuid: newUUID, + text: markdownNode.title, + details: markdownNode.content, + location: [diffLocation.x + deepLevel * 50, diffLocation.y + visitedCount * 100], + size: [100, 100], + }); + StageManager.addTextNode(node); + monoStack.push(node, deepLevel); + // 连接父节点 + const fatherNode = monoStack.unsafeGet(monoStack.length - 2); + StageManager.connectEntity(fatherNode, node); + }; + + dfsMarkdownNode(markdownJson[0], 0); + } +} diff --git a/app/src/core/stage/stageManager/concreteMethods/StageNodeConnector.tsx b/app/src/core/stage/stageManager/concreteMethods/StageNodeConnector.tsx index 6fc8af07..9410fe6d 100644 --- a/app/src/core/stage/stageManager/concreteMethods/StageNodeConnector.tsx +++ b/app/src/core/stage/stageManager/concreteMethods/StageNodeConnector.tsx @@ -1,6 +1,6 @@ import { v4 as uuidv4 } from "uuid"; import { ConnectableEntity } from "../../stageObject/abstract/ConnectableEntity"; -import { CublicCatmullRomSplineEdge } from "../../stageObject/association/CublicCatmullRomSplineEdge"; +import { CubicCatmullRomSplineEdge } from "../../stageObject/association/CubicCatmullRomSplineEdge"; import { LineEdge } from "../../stageObject/association/LineEdge"; import { ConnectPoint } from "../../stageObject/entity/ConnectPoint"; import { GraphMethods } from "../basicMethods/GraphMethods"; @@ -68,7 +68,7 @@ export namespace StageNodeConnector { if (!isConnectable(fromNode, toNode)) { return; } - const newEdge = CublicCatmullRomSplineEdge.fromTwoEntity(fromNode, toNode); + const newEdge = CubicCatmullRomSplineEdge.fromTwoEntity(fromNode, toNode); StageManager.addCrEdge(newEdge); StageManager.updateReferences(); } diff --git a/app/src/core/stage/stageManager/concreteMethods/StageNodeRotate.tsx b/app/src/core/stage/stageManager/concreteMethods/StageNodeRotate.tsx new file mode 100644 index 00000000..5e670474 --- /dev/null +++ b/app/src/core/stage/stageManager/concreteMethods/StageNodeRotate.tsx @@ -0,0 +1,117 @@ +import { Color } from "../../../dataStruct/Color"; +import { ProgressNumber } from "../../../dataStruct/ProgressNumber"; +import { Vector } from "../../../dataStruct/Vector"; +import { LineEffect } from "../../../service/feedbackService/effectEngine/concrete/LineEffect"; +import { Stage } from "../../Stage"; +import { ConnectableEntity } from "../../stageObject/abstract/ConnectableEntity"; +import { GraphMethods } from "../basicMethods/GraphMethods"; +import { StageManager } from "../StageManager"; +import { StageEntityMoveManager } from "./StageEntityMoveManager"; + +/** + * 所有和旋转相关的操作 + */ +export namespace StageNodeRotate { + /** + * 通过拖拽边的方式来旋转节点 + * 会查找所有选中的边,但只能旋转一个边 + * @param lastMoveLocation + * @param diffLocation + */ + export function moveEdges(lastMoveLocation: Vector, diffLocation: Vector) { + for (const edge of StageManager.getLineEdges()) { + if (edge.isSelected) { + const startMouseDragLocation = lastMoveLocation.clone(); + const endMouseDragLocation = startMouseDragLocation.add(diffLocation); + const vectorStart = startMouseDragLocation.subtract(edge.source.geometryCenter); + const vectorEnd = endMouseDragLocation.subtract(edge.source.geometryCenter); + let degrees = vectorStart.angleToSigned(vectorEnd); + // degrees一直是正数 + if (Number.isNaN(degrees)) { + degrees = 0; + } + const sourceEntity = StageManager.getConnectableEntityByUUID(edge.source.uuid); + const targetEntity = StageManager.getConnectableEntityByUUID(edge.target.uuid); + + if (sourceEntity && targetEntity) { + rotateNodeDfs( + StageManager.getConnectableEntityByUUID(edge.source.uuid)!, + StageManager.getConnectableEntityByUUID(edge.target.uuid)!, + degrees, + [edge.source.uuid], + ); + } else { + console.error("source or target entity not found"); + } + break; // 只旋转一个边 + } + } + } + + /** + * + * @param rotateCenterNode 递归开始的节点 + * @param currentNode 当前递归遍历到的节点 + * @param degrees 旋转角度 + * @param visitedUUIDs 已经访问过的节点的uuid列表,用于避免死循环 + */ + export function rotateNodeDfs( + rotateCenterNode: ConnectableEntity, + currentNode: ConnectableEntity, + degrees: number, + visitedUUIDs: string[], + ): void { + const rotateCenterLocation = rotateCenterNode.geometryCenter; + // 先旋转自己 + + const centerToChildVector = currentNode.geometryCenter.subtract(rotateCenterLocation); + + const centerToChildVectorRotated = centerToChildVector.rotateDegrees(degrees); + + StageEntityMoveManager.moveEntityUtils(currentNode, centerToChildVectorRotated.subtract(centerToChildVector)); + // 再旋转子节点 + for (const child of GraphMethods.nodeChildrenArray(currentNode)) { + if (visitedUUIDs.includes(child.uuid)) { + continue; + } + visitedUUIDs.push(child.uuid); + const childNode = StageManager.getConnectableEntityByUUID(child.uuid); + if (!childNode) { + console.error("child node not found"); + continue; + } + const midPoint = Vector.fromTwoPointsCenter(currentNode.geometryCenter, childNode.geometryCenter); + + Stage.effectMachine.addEffect( + new LineEffect( + new ProgressNumber(0, 20), + currentNode.geometryCenter, + midPoint, + new Color(255, 255, 255, 0), + new Color(255, 255, 255, 0.5), + Math.abs(degrees), + ), + ); + Stage.effectMachine.addEffect( + new LineEffect( + new ProgressNumber(0, 20), + midPoint, + childNode.geometryCenter, + new Color(255, 255, 255, 0.5), + new Color(255, 255, 255, 0), + Math.abs(degrees), + ), + ); + + rotateNodeDfs( + rotateCenterNode, + // 2024年10月6日:发现打开文件后,旋转节点无法带动子树,只能传递一层。 + // child, + childNode, + degrees, + // visitedUUIDs.concat(currentNode.uuid), + visitedUUIDs, + ); + } + } +} diff --git a/app/src/core/stage/stageManager/concreteMethods/StageObjectSelectCounter.tsx b/app/src/core/stage/stageManager/concreteMethods/StageObjectSelectCounter.tsx index b55df824..111ec2be 100644 --- a/app/src/core/stage/stageManager/concreteMethods/StageObjectSelectCounter.tsx +++ b/app/src/core/stage/stageManager/concreteMethods/StageObjectSelectCounter.tsx @@ -1,6 +1,6 @@ import { Association } from "../../stageObject/abstract/Association"; import { Entity } from "../../stageObject/abstract/StageEntity"; -import { CublicCatmullRomSplineEdge } from "../../stageObject/association/CublicCatmullRomSplineEdge"; +import { CubicCatmullRomSplineEdge } from "../../stageObject/association/CubicCatmullRomSplineEdge"; import { Edge } from "../../stageObject/association/Edge"; import { MultiTargetUndirectedEdge } from "../../stageObject/association/MutiTargetUndirectedEdge"; import { ImageNode } from "../../stageObject/entity/ImageNode"; @@ -72,7 +72,7 @@ export namespace StageObjectSelectCounter { } if (stageObject instanceof Edge) { selectedEdgeCount++; - if (stageObject instanceof CublicCatmullRomSplineEdge) { + if (stageObject instanceof CubicCatmullRomSplineEdge) { selectedCREdgeCount++; } } diff --git a/app/src/core/stage/stageManager/concreteMethods/StageSerializedAdder.tsx b/app/src/core/stage/stageManager/concreteMethods/StageSerializedAdder.tsx index 9d41deac..58c6c44a 100644 --- a/app/src/core/stage/stageManager/concreteMethods/StageSerializedAdder.tsx +++ b/app/src/core/stage/stageManager/concreteMethods/StageSerializedAdder.tsx @@ -10,7 +10,7 @@ import { PortalNode } from "../../stageObject/entity/PortalNode"; import { PenStroke } from "../../stageObject/entity/PenStroke"; import { UrlNode } from "../../stageObject/entity/UrlNode"; import { Entity } from "../../stageObject/abstract/StageEntity"; -import { CublicCatmullRomSplineEdge } from "../../stageObject/association/CublicCatmullRomSplineEdge"; +import { CubicCatmullRomSplineEdge } from "../../stageObject/association/CubicCatmullRomSplineEdge"; import { ImageNode } from "../../stageObject/entity/ImageNode"; /** * 直接向舞台中添加序列化数据 @@ -50,8 +50,8 @@ export namespace StageSerializedAdder { for (const edge of updatedSerializedData.associations) { if (Serialized.isLineEdge(edge)) { StageManager.addLineEdge(new LineEdge(edge)); - } else if (Serialized.isCublicCatmullRomSplineEdge(edge)) { - StageManager.addCrEdge(new CublicCatmullRomSplineEdge(edge)); + } else if (Serialized.isCubicCatmullRomSplineEdge(edge)) { + StageManager.addCrEdge(new CubicCatmullRomSplineEdge(edge)); } } StageManager.updateReferences(); diff --git a/app/src/core/stage/stageObject/association/CublicCatmullRomSplineEdge.tsx b/app/src/core/stage/stageObject/association/CubicCatmullRomSplineEdge.tsx similarity index 85% rename from app/src/core/stage/stageObject/association/CublicCatmullRomSplineEdge.tsx rename to app/src/core/stage/stageObject/association/CubicCatmullRomSplineEdge.tsx index b4bdee23..9a78d887 100644 --- a/app/src/core/stage/stageObject/association/CublicCatmullRomSplineEdge.tsx +++ b/app/src/core/stage/stageObject/association/CubicCatmullRomSplineEdge.tsx @@ -1,6 +1,6 @@ import { v4 as uuidv4 } from "uuid"; import { Serialized } from "../../../../types/node"; -import { CublicCatmullRomSpline } from "../../../dataStruct/shape/CublicCatmullRomSpline"; +import { CubicCatmullRomSpline } from "../../../dataStruct/shape/CubicCatmullRomSpline"; import { Vector } from "../../../dataStruct/Vector"; import { ConnectableEntity } from "../abstract/ConnectableEntity"; import { CollisionBox } from "../collisionBox/collisionBox"; @@ -17,7 +17,7 @@ import { Color } from "../../../dataStruct/Color"; * alpha 不用自己修改了,这个是0.5固定值了,只会微微影响形状 * tension 控制曲线的弯曲程度,0是折线。 */ -export class CublicCatmullRomSplineEdge extends Edge { +export class CubicCatmullRomSplineEdge extends Edge { public uuid: string; public text: string; protected _source: ConnectableEntity; @@ -49,18 +49,18 @@ export class CublicCatmullRomSplineEdge extends Edge { return this._collisionBox; } - static fromTwoEntity(source: ConnectableEntity, target: ConnectableEntity): CublicCatmullRomSplineEdge { + static fromTwoEntity(source: ConnectableEntity, target: ConnectableEntity): CubicCatmullRomSplineEdge { // 处理控制点,控制点必须有四个,1 2 3 4,12可重叠,34可重叠 const startLocation = source.geometryCenter.clone(); const endLocation = target.geometryCenter.clone(); const line = Edge.getCenterLine(source, target); - const result = new CublicCatmullRomSplineEdge({ + const result = new CubicCatmullRomSplineEdge({ source: source.uuid, target: target.uuid, text: "", uuid: uuidv4(), - type: "core:cublic_catmull_rom_spline_edge", + type: "core:cubic_catmull_rom_spline_edge", alpha: 0.5, tension: 0, color: [0, 0, 0, 0], @@ -88,7 +88,7 @@ export class CublicCatmullRomSplineEdge extends Edge { controlPoints, sourceRectRate, targetRectRate, - }: Serialized.CublicCatmullRomSplineEdge /** true表示解析状态,false表示解析完毕 */, + }: Serialized.CubicCatmullRomSplineEdge /** true表示解析状态,false表示解析完毕 */, public unknown = false, ) { super(); @@ -104,12 +104,12 @@ export class CublicCatmullRomSplineEdge extends Edge { this.controlPoints = controlPoints.map((item) => new Vector(item[0], item[1])); this.setSourceRectangleRate(new Vector(...sourceRectRate)); this.setTargetRectangleRate(new Vector(...targetRectRate)); - this._collisionBox = new CollisionBox([new CublicCatmullRomSpline(this.controlPoints, this.alpha, this.tension)]); + this._collisionBox = new CollisionBox([new CubicCatmullRomSpline(this.controlPoints, this.alpha, this.tension)]); } - public getShape(): CublicCatmullRomSpline { + public getShape(): CubicCatmullRomSpline { // 重新计算形状 - const crShape = this._collisionBox.shapeList[0] as CublicCatmullRomSpline; + const crShape = this._collisionBox.shapeList[0] as CubicCatmullRomSpline; this.autoUpdateControlPoints(); // ? return crShape; } @@ -135,14 +135,14 @@ export class CublicCatmullRomSplineEdge extends Edge { this.controlPoints = [startLocation, line.start].concat(middleControlPoints).concat([line.end, endLocation]); } // 重新生成新的形状 - this._collisionBox.shapeList = [new CublicCatmullRomSpline(this.controlPoints, this.alpha, this.tension)]; + this._collisionBox.shapeList = [new CubicCatmullRomSpline(this.controlPoints, this.alpha, this.tension)]; } /** * 获取箭头的位置和方向 */ getArrowHead(): { location: Vector; direction: Vector } { - const crShape = this._collisionBox.shapeList[0] as CublicCatmullRomSpline; + const crShape = this._collisionBox.shapeList[0] as CubicCatmullRomSpline; const location = crShape.controlPoints[crShape.controlPoints.length - 2].clone(); const lines = crShape.computeFunction(); const funcs = lines[lines.length - 1]; diff --git a/app/src/types/node.tsx b/app/src/types/node.tsx index 229a669d..bba5c962 100644 --- a/app/src/types/node.tsx +++ b/app/src/types/node.tsx @@ -159,11 +159,11 @@ export namespace Serialized { export function isLineEdge(obj: StageObject): obj is LineEdge { return obj.type === "core:line_edge"; } - export function isCublicCatmullRomSplineEdge(obj: StageObject): obj is CublicCatmullRomSplineEdge { - return obj.type === "core:cublic_catmull_rom_spline_edge"; + export function isCubicCatmullRomSplineEdge(obj: StageObject): obj is CubicCatmullRomSplineEdge { + return obj.type === "core:cubic_catmull_rom_spline_edge"; } - export type CublicCatmullRomSplineEdge = Edge & { - type: "core:cublic_catmull_rom_spline_edge"; + export type CubicCatmullRomSplineEdge = Edge & { + type: "core:cubic_catmull_rom_spline_edge"; text: string; controlPoints: Vector[]; alpha: number; @@ -174,7 +174,7 @@ export namespace Serialized { export function isCoreEntity(obj: StageObject): obj is CoreEntity { return obj.type.startsWith("core:"); } - export type CoreAssociation = LineEdge | CublicCatmullRomSplineEdge | MultiTargetUndirectedEdge; + export type CoreAssociation = LineEdge | CubicCatmullRomSplineEdge | MultiTargetUndirectedEdge; export type File = { version: typeof StageDumper.latestVersion; From 373311bcf6da72e9523b9368b3959b9f2f6634c9 Mon Sep 17 00:00:00 2001 From: brokenstring314 <15635128186@163.com> Date: Thu, 8 May 2025 12:27:07 +0800 Subject: [PATCH 2/2] =?UTF-8?q?=F0=9F=90=9B=20=E4=BF=AE=E5=A4=8D=E5=A4=9A?= =?UTF-8?q?=E4=B8=AA=E5=BB=B6=E8=BF=9F=E7=BA=BF=E6=97=B6step=E9=80=92?= =?UTF-8?q?=E5=A2=9E=E5=8F=A0=E5=8A=A0=EF=BC=8C=E4=BF=AE=E5=A4=8DCtrl?= =?UTF-8?q?=E5=B7=A6=E9=94=AE=E5=8D=95=E5=87=BB=E8=BE=B9=E6=97=B6=E7=9A=84?= =?UTF-8?q?=E6=8A=A5=E9=94=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../concrete/ControllerEntityClickSelectAndMove.tsx | 2 ++ .../autoComputeEngine/functions/nodeLogic.tsx | 7 ++----- .../dataGenerateService/autoComputeEngine/mainTick.tsx | 2 ++ 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/app/src/core/service/controlService/controller/concrete/ControllerEntityClickSelectAndMove.tsx b/app/src/core/service/controlService/controller/concrete/ControllerEntityClickSelectAndMove.tsx index 97b73b9e..63d02f80 100644 --- a/app/src/core/service/controlService/controller/concrete/ControllerEntityClickSelectAndMove.tsx +++ b/app/src/core/service/controlService/controller/concrete/ControllerEntityClickSelectAndMove.tsx @@ -50,6 +50,8 @@ class ControllerEntityClickSelectAndMoveClass extends ControllerClass { } else if (Controller.pressingKeySet.has("shift")) { // shift 按下,只选中节点 clickedStageObject.isSelected = true; + // 没有实体被选中则return + if (StageManager.getSelectedEntities().length === 0) return; const rectangles = StageManager.getSelectedEntities().map((entity) => entity.collisionBox.getRectangle()); const boundingRectangle = Rectangle.getBoundingRectangle(rectangles); Stage.effectMachine.addEffect(RectangleRenderEffect.fromShiftClickSelect(boundingRectangle)); diff --git a/app/src/core/service/dataGenerateService/autoComputeEngine/functions/nodeLogic.tsx b/app/src/core/service/dataGenerateService/autoComputeEngine/functions/nodeLogic.tsx index 09306861..59b6356d 100644 --- a/app/src/core/service/dataGenerateService/autoComputeEngine/functions/nodeLogic.tsx +++ b/app/src/core/service/dataGenerateService/autoComputeEngine/functions/nodeLogic.tsx @@ -25,10 +25,10 @@ import { ConnectPoint } from "../../../../stage/stageObject/entity/ConnectPoint" */ export namespace NodeLogic { export const delayStates: Map> = new Map(); - let step: number = 0; + /* eslint-disable prefer-const */ + export let step: number = 0; // step 是一个计数器,每当逻辑引擎实际执行一次时,step 就会加一 // TODO: 可以考虑把 step 放到逻辑引擎层面,甚至可以出一个节点获取当前步数,可以加一个每次只运行一步的快捷键 - // 现在的好处是只有在用延迟复制时才会有这个计数器,其他时候step不存在 /** * 输入三个数字节点,并将所有的孩子节点更改为相应的颜色 * @param fatherNodes @@ -686,13 +686,10 @@ export namespace NodeLogic { // eslint-disable-next-line @typescript-eslint/no-unused-vars _childNodes: ConnectableEntity[], ): string[] { - step++; if (fatherNodes.length < 4) { // 多了一个逻辑节点本身,所以实际进来的节点比延迟复制需要的节点节点多一个 return ["Error: input node contains less than 3 nodes"]; } - console.log("delayCopy", fatherNodes); - console.log(delayStates); if ( fatherNodes[0] instanceof TextNode && fatherNodes[1] instanceof TextNode && diff --git a/app/src/core/service/dataGenerateService/autoComputeEngine/mainTick.tsx b/app/src/core/service/dataGenerateService/autoComputeEngine/mainTick.tsx index ded108bc..749a74da 100644 --- a/app/src/core/service/dataGenerateService/autoComputeEngine/mainTick.tsx +++ b/app/src/core/service/dataGenerateService/autoComputeEngine/mainTick.tsx @@ -201,6 +201,8 @@ export function autoComputeEngineTick(tickNumber: number) { )) { computeEdge(edge); } + NodeLogic.step++; + // 逻辑引擎执行一步,计数器+1 } export function isTextNodeLogic(node: TextNode): boolean {