From e08b44ff25265fb4ad7b453ed487c915b16a2f67 Mon Sep 17 00:00:00 2001 From: Victor Giers Date: Wed, 15 Apr 2026 08:06:13 +0200 Subject: [PATCH] Add commands for creating radial prism and wedge brushes --- .../create-radial-prism-brush-command.ts | 97 +++++++++++++++++++ src/commands/create-wedge-brush-command.ts | 95 ++++++++++++++++++ 2 files changed, 192 insertions(+) create mode 100644 src/commands/create-radial-prism-brush-command.ts create mode 100644 src/commands/create-wedge-brush-command.ts diff --git a/src/commands/create-radial-prism-brush-command.ts b/src/commands/create-radial-prism-brush-command.ts new file mode 100644 index 00000000..ad424e52 --- /dev/null +++ b/src/commands/create-radial-prism-brush-command.ts @@ -0,0 +1,97 @@ +import type { ToolMode } from "../core/tool-mode"; +import { + createRadialPrismBrush, + DEFAULT_BOX_BRUSH_CENTER, + DEFAULT_BOX_BRUSH_SIZE +} from "../document/brushes"; +import { + DEFAULT_GRID_SIZE, + snapPositiveSizeToGrid, + snapVec3ToGrid +} from "../geometry/grid-snapping"; + +import { createOpaqueId } from "../core/ids"; +import type { EditorSelection } from "../core/selection"; +import type { Vec3 } from "../core/vector"; + +import { + cloneSelectionForCommand, + removeBrush, + setSingleBrushSelection +} from "./brush-command-helpers"; +import type { EditorCommand } from "./command"; + +interface CreateRadialPrismBrushCommandOptions { + center?: Vec3; + size?: Vec3; + sideCount?: number; + snapToGrid?: boolean; + gridSize?: number; +} + +export function createCreateRadialPrismBrushCommand( + options: CreateRadialPrismBrushCommandOptions = {} +): EditorCommand { + const snapToGrid = options.snapToGrid ?? true; + const brush = createRadialPrismBrush({ + center: + snapToGrid === false + ? options.center ?? DEFAULT_BOX_BRUSH_CENTER + : snapVec3ToGrid( + options.center ?? DEFAULT_BOX_BRUSH_CENTER, + options.gridSize ?? DEFAULT_GRID_SIZE + ), + size: + snapToGrid === false + ? options.size ?? DEFAULT_BOX_BRUSH_SIZE + : snapPositiveSizeToGrid( + options.size ?? DEFAULT_BOX_BRUSH_SIZE, + options.gridSize ?? DEFAULT_GRID_SIZE + ), + sideCount: options.sideCount + }); + + let previousSelection: EditorSelection | null = null; + let previousToolMode: ToolMode | null = null; + + return { + id: createOpaqueId("command"), + label: "Create radial prism brush", + execute(context) { + const currentDocument = context.getDocument(); + + if (currentDocument.brushes[brush.id] !== undefined) { + throw new Error(`Radial prism brush ${brush.id} already exists.`); + } + + if (previousSelection === null) { + previousSelection = cloneSelectionForCommand(context.getSelection()); + } + + if (previousToolMode === null) { + previousToolMode = context.getToolMode(); + } + + context.setDocument({ + ...currentDocument, + brushes: { + ...currentDocument.brushes, + [brush.id]: brush + } + }); + context.setSelection(setSingleBrushSelection(brush.id)); + context.setToolMode("select"); + }, + undo(context) { + context.setDocument(removeBrush(context.getDocument(), brush.id)); + + if (previousSelection !== null) { + context.setSelection(previousSelection); + } + + if (previousToolMode !== null) { + context.setToolMode(previousToolMode); + } + } + }; +} diff --git a/src/commands/create-wedge-brush-command.ts b/src/commands/create-wedge-brush-command.ts new file mode 100644 index 00000000..072a0002 --- /dev/null +++ b/src/commands/create-wedge-brush-command.ts @@ -0,0 +1,95 @@ +import type { ToolMode } from "../core/tool-mode"; +import { + createWedgeBrush, + DEFAULT_BOX_BRUSH_CENTER, + DEFAULT_BOX_BRUSH_SIZE +} from "../document/brushes"; +import { + DEFAULT_GRID_SIZE, + snapPositiveSizeToGrid, + snapVec3ToGrid +} from "../geometry/grid-snapping"; + +import { createOpaqueId } from "../core/ids"; +import type { EditorSelection } from "../core/selection"; +import type { Vec3 } from "../core/vector"; + +import { + cloneSelectionForCommand, + removeBrush, + setSingleBrushSelection +} from "./brush-command-helpers"; +import type { EditorCommand } from "./command"; + +interface CreateWedgeBrushCommandOptions { + center?: Vec3; + size?: Vec3; + snapToGrid?: boolean; + gridSize?: number; +} + +export function createCreateWedgeBrushCommand( + options: CreateWedgeBrushCommandOptions = {} +): EditorCommand { + const snapToGrid = options.snapToGrid ?? true; + const brush = createWedgeBrush({ + center: + snapToGrid === false + ? options.center ?? DEFAULT_BOX_BRUSH_CENTER + : snapVec3ToGrid( + options.center ?? DEFAULT_BOX_BRUSH_CENTER, + options.gridSize ?? DEFAULT_GRID_SIZE + ), + size: + snapToGrid === false + ? options.size ?? DEFAULT_BOX_BRUSH_SIZE + : snapPositiveSizeToGrid( + options.size ?? DEFAULT_BOX_BRUSH_SIZE, + options.gridSize ?? DEFAULT_GRID_SIZE + ) + }); + + let previousSelection: EditorSelection | null = null; + let previousToolMode: ToolMode | null = null; + + return { + id: createOpaqueId("command"), + label: "Create wedge brush", + execute(context) { + const currentDocument = context.getDocument(); + + if (currentDocument.brushes[brush.id] !== undefined) { + throw new Error(`Wedge brush ${brush.id} already exists.`); + } + + if (previousSelection === null) { + previousSelection = cloneSelectionForCommand(context.getSelection()); + } + + if (previousToolMode === null) { + previousToolMode = context.getToolMode(); + } + + context.setDocument({ + ...currentDocument, + brushes: { + ...currentDocument.brushes, + [brush.id]: brush + } + }); + context.setSelection(setSingleBrushSelection(brush.id)); + context.setToolMode("select"); + }, + undo(context) { + context.setDocument(removeBrush(context.getDocument(), brush.id)); + + if (previousSelection !== null) { + context.setSelection(previousSelection); + } + + if (previousToolMode !== null) { + context.setToolMode(previousToolMode); + } + } + }; +}