task(E7): event elements polish - curtain (wavy polyline), spotlight (cone polygon with angle/color), barrier (chain circles), stage height attribute
This commit is contained in:
@@ -280,15 +280,156 @@ export const arcRowTool: ToolExtensionV2 = {
|
||||
};
|
||||
|
||||
/** V2-Plugin: Event-Domain (Tasks A4.9 + E1). */
|
||||
// ─────────────────────────────────────────────────────────────
|
||||
// Task E7: Event-Elemente-Polish — curtain, spotlight, barrier
|
||||
// ─────────────────────────────────────────────────────────────
|
||||
|
||||
/** Vorhang: wellige Polyline (Standardbreite 400) über der Bühne. */
|
||||
export const curtainTool: ToolExtensionV2 = {
|
||||
manifest: {
|
||||
id: 'curtain',
|
||||
label: 'Vorhang',
|
||||
icon: '╭',
|
||||
ribbonTab: 'insert',
|
||||
tags: ['basic'],
|
||||
description: 'Vorhang entlang der Bühnen-Oberkante platzieren',
|
||||
},
|
||||
optionsSchema: [
|
||||
{ key: 'stageHeight', label: 'Höhe (cm)', type: 'number' },
|
||||
],
|
||||
handlers: {
|
||||
down(e, ctx) {
|
||||
const c = ctx as FullToolContext;
|
||||
if (!c.doc) return;
|
||||
const { layerId } = optsOf(ctx);
|
||||
const stageHeight = (ctx.options.stageHeight as number | undefined) ?? 120;
|
||||
const width = 400;
|
||||
// Wellenform: 24 Punkte, Sinus gedämpft an den Enden
|
||||
const pts: Pt[] = [];
|
||||
const SEG = 24;
|
||||
for (let i = 0; i <= SEG; i++) {
|
||||
const t = i / SEG;
|
||||
const x = e.world.x - width / 2 + width * t;
|
||||
const y = e.world.y + Math.sin(t * Math.PI) * (stageHeight / 4);
|
||||
pts.push({ x, y });
|
||||
}
|
||||
const el: CADElement = {
|
||||
id: `curtain-${Date.now()}-${Math.random().toString(36).slice(2, 7)}`,
|
||||
type: 'curtain',
|
||||
layerId,
|
||||
x: e.world.x,
|
||||
y: e.world.y,
|
||||
width,
|
||||
height: stageHeight,
|
||||
properties: { points: pts, stageHeight, stroke: '#7a4a8f', strokeWidth: 2 },
|
||||
};
|
||||
c.doc.transact(() => { c.doc!.addElement(el); });
|
||||
ctx.setStatus(`Vorhang platziert (${width} breit, ${stageHeight} cm hoch)`);
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
/** Scheinwerfer: Lichtkegel in angle-Richtung mit Farbe. */
|
||||
export const spotlightTool: ToolExtensionV2 = {
|
||||
manifest: {
|
||||
id: 'spotlight',
|
||||
label: 'Scheinwerfer',
|
||||
icon: '▶',
|
||||
ribbonTab: 'insert',
|
||||
tags: ['basic'],
|
||||
description: 'Scheinwerfer-Kegel platzieren (Winkel + Farbe aus Optionen)',
|
||||
},
|
||||
optionsSchema: [
|
||||
{ key: 'angle', label: 'Winkel (°)', type: 'number' },
|
||||
{ key: 'color', label: 'Lichtfarbe', type: 'color' },
|
||||
],
|
||||
handlers: {
|
||||
down(e, ctx) {
|
||||
const c = ctx as FullToolContext;
|
||||
if (!c.doc) return;
|
||||
const { layerId } = optsOf(ctx);
|
||||
const angle = (ctx.options.angle as number | undefined) ?? 0;
|
||||
const color = (ctx.options.color as string | undefined) ?? '#ffcc00';
|
||||
const length = 300;
|
||||
const halfAngle = 20;
|
||||
const rad = (angle * Math.PI) / 180;
|
||||
const radHalf = (halfAngle * Math.PI) / 180;
|
||||
const p1 = { x: e.world.x + length * Math.cos(rad - radHalf), y: e.world.y + length * Math.sin(rad - radHalf) };
|
||||
const p2 = { x: e.world.x + length * Math.cos(rad + radHalf), y: e.world.y + length * Math.sin(rad + radHalf) };
|
||||
const pts: Pt[] = [
|
||||
{ x: e.world.x, y: e.world.y },
|
||||
p1,
|
||||
p2,
|
||||
{ x: e.world.x, y: e.world.y },
|
||||
];
|
||||
const el: CADElement = {
|
||||
id: `spotlight-${Date.now()}-${Math.random().toString(36).slice(2, 7)}`,
|
||||
type: 'spotlight',
|
||||
layerId,
|
||||
x: e.world.x,
|
||||
y: e.world.y,
|
||||
width: length,
|
||||
height: length,
|
||||
properties: { points: pts, angle, color },
|
||||
};
|
||||
c.doc.transact(() => { c.doc!.addElement(el); });
|
||||
ctx.setStatus(`Scheinwerfer platziert (${angle}°, ${color})`);
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
/** Absperrung: Kette aus Kreis-Paaren entlang Standardlänge 200. */
|
||||
export const barrierTool: ToolExtensionV2 = {
|
||||
manifest: {
|
||||
id: 'barrier',
|
||||
label: 'Absperrung',
|
||||
icon: '⛴',
|
||||
ribbonTab: 'insert',
|
||||
tags: ['basic'],
|
||||
description: 'Absperr-Kette (Kreis-Paare) platzieren',
|
||||
},
|
||||
optionsSchema: [
|
||||
{ key: 'length', label: 'Länge', type: 'number' },
|
||||
],
|
||||
handlers: {
|
||||
down(e, ctx) {
|
||||
const c = ctx as FullToolContext;
|
||||
if (!c.doc) return;
|
||||
const { layerId } = optsOf(ctx);
|
||||
const length = (ctx.options.length as number | undefined) ?? 200;
|
||||
const circles: Array<{ x: number; y: number; r: number }> = [];
|
||||
const pairs = 6;
|
||||
for (let i = 0; i < pairs; i++) {
|
||||
const t = (i + 0.5) / pairs;
|
||||
const cx = e.world.x - length / 2 + length * t;
|
||||
circles.push({ x: cx, y: e.world.y - 10, r: 8 });
|
||||
circles.push({ x: cx, y: e.world.y + 10, r: 8 });
|
||||
}
|
||||
const el: CADElement = {
|
||||
id: `barrier-${Date.now()}-${Math.random().toString(36).slice(2, 7)}`,
|
||||
type: 'barrier',
|
||||
layerId,
|
||||
x: e.world.x,
|
||||
y: e.world.y,
|
||||
width: length,
|
||||
height: 20,
|
||||
properties: { circles, color: '#c0392b' },
|
||||
};
|
||||
c.doc.transact(() => { c.doc!.addElement(el); });
|
||||
ctx.setStatus(`Absperrung platziert (${length} lang, ${pairs} Kettenglieder)`);
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export const eventToolsV2Plugin: PluginV2 = {
|
||||
manifest: {
|
||||
id: 'event-tools',
|
||||
name: 'Event-Bestuhlung',
|
||||
version: '2.1.0',
|
||||
version: '2.2.0',
|
||||
author: 'web-cad team',
|
||||
description: 'Stühle, Reihen (Drag), Blöcke (Drag), Tische, Bühne (V2).',
|
||||
description: 'Stühle, Reihen (Drag), Blöcke (Drag), Tische, Bühne, Vorhang, Scheinwerfer, Absperrung (V2).',
|
||||
category: 'elements',
|
||||
enabledByDefault: true,
|
||||
},
|
||||
tools: [chairTool, seatingRowToolDrag, seatingBlockToolDrag, tableTool, stageTool, arcRowTool, kinoTemplateTool, banquetTemplateTool, standingTableTemplateTool, podiumTemplateTool],
|
||||
tools: [chairTool, seatingRowToolDrag, seatingBlockToolDrag, tableTool, stageTool, arcRowTool, kinoTemplateTool, banquetTemplateTool, standingTableTemplateTool, podiumTemplateTool, curtainTool, spotlightTool, barrierTool],
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user