tarinai/js/physics_shape_editor_system.js
2026-06-28 23:07:40 +09:00

70 lines
2.7 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"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({
MODE_LABELS,
TEMPLATE_LABELS,
ACTION_LABELS,
decorateToolbar,
templateSegments,
pointSegmentDistance,
});
})(typeof window !== "undefined" ? window : globalThis);