tarinai/js/physics_shape_editor_system.js

67 lines
2.6 KiB
JavaScript
Raw Normal View History

2026-06-28 23:07:40 +09:00
"use strict";
// Layer: ui/physics-shape-editor
// Shared button labels/templates for rotator, reciprocator, and poison-block
// segment editors. Low-level editor pointer behavior remains in placement log.
(function (global) {
const MODE_LABELS = Object.freeze({
line: "📏 直線",
free: "✎ 自由描画",
erase: "⌫ 消しゴム",
});
const TEMPLATE_LABELS = Object.freeze({
bar: "┃ 棒",
cross: " 十字",
circle: "○ 円",
});
const ACTION_LABELS = Object.freeze({
undo: "↶ 一つ戻す",
clear: "🗑 全消し",
});
function templateSegments(name) {
if (name === "bar") return [[-130, 0, 130, 0]];
if (name === "cross") return [[-118, 0, 118, 0], [0, -90, 0, 90]];
if (name === "circle") {
const segments = [];
const n = 18, r = 108;
for (let i = 0; i < n; i += 1) {
const a = i / n * Math.PI * 2;
const b = (i + 1) / n * Math.PI * 2;
segments.push([Math.cos(a) * r, Math.sin(a) * r, Math.cos(b) * r, Math.sin(b) * r]);
}
return segments;
}
return null;
}
function decorateToolbar(dialog, prefix = "rotator") {
if (!dialog) return false;
for (const btn of dialog.querySelectorAll(`[data-${prefix}-mode]`)) {
const key = btn.dataset[`${prefix}Mode`];
if (MODE_LABELS[key]) { btn.textContent = MODE_LABELS[key]; btn.title = MODE_LABELS[key].replace(/^[^\s]+\s*/, ""); }
}
for (const btn of dialog.querySelectorAll(`[data-${prefix}-template]`)) {
const key = btn.dataset[`${prefix}Template`];
if (TEMPLATE_LABELS[key]) { btn.textContent = TEMPLATE_LABELS[key]; btn.title = TEMPLATE_LABELS[key].replace(/^[^\s]+\s*/, ""); }
}
const undo = dialog.querySelector(`#${prefix}Undo`);
const clear = dialog.querySelector(`#${prefix}Clear`);
if (undo) undo.textContent = ACTION_LABELS.undo;
if (clear) clear.textContent = ACTION_LABELS.clear;
return true;
}
function pointSegmentDistance(p, seg) {
if (!p || !Array.isArray(seg) || seg.length < 4) return Infinity;
const x1 = Number(seg[0]) || 0, y1 = Number(seg[1]) || 0;
const x2 = Number(seg[2]) || 0, y2 = Number(seg[3]) || 0;
const dx = x2 - x1, dy = y2 - y1;
const lenSq = dx * dx + dy * dy;
if (lenSq <= 0.0001) return Math.hypot(p.x - x1, p.y - y1);
const u = Math.max(0, Math.min(1, ((p.x - x1) * dx + (p.y - y1) * dy) / lenSq));
return Math.hypot(p.x - (x1 + dx * u), p.y - (y1 + dy * u));
}
global.TarinaiPhysicsShapeEditorSystem = Object.freeze({
decorateToolbar,
templateSegments,
pointSegmentDistance,
});
})(typeof window !== "undefined" ? window : globalThis);