@things-factory/figure-ui 10.1.270 → 10.1.272
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/client/graphql/index.ts +2 -0
- package/client/modeller/canvas.ts +4 -2
- package/client/modeller/clips.ts +74 -4
- package/client/modeller/data-interface.ts +14 -0
- package/client/modeller/editor-styles.ts +11 -0
- package/client/modeller/editor.ts +39 -11
- package/client/modeller/fasten-form.ts +73 -3
- package/client/modeller/fasten-geometry.ts +11 -1
- package/client/modeller/figure-cavity-drawing.ts +1 -3
- package/client/modeller/figure-clips.ts +101 -8
- package/client/modeller/figure-fasten-dialog.ts +41 -30
- package/client/modeller/figure-fasten-drawing.ts +5 -4
- package/client/modeller/figure-first-save.ts +4 -3
- package/client/modeller/figure-links.ts +85 -28
- package/client/modeller/figure-preview.ts +50 -4
- package/client/modeller/figure-size-editor.ts +7 -2
- package/client/modeller/first-save.ts +8 -0
- package/client/modeller/focus-on-render.ts +4 -0
- package/client/modeller/palette.ts +27 -0
- package/client/modeller/pivot.ts +76 -0
- package/client/modeller/product-session.ts +5 -1
- package/client/modeller/size-response.ts +14 -0
- package/client/modeller/stage-model.ts +50 -6
- package/client/types.ts +2 -0
- package/dist-client/graphql/index.js +2 -0
- package/dist-client/graphql/index.js.map +1 -1
- package/dist-client/modeller/canvas.d.ts +1 -0
- package/dist-client/modeller/canvas.js +3 -2
- package/dist-client/modeller/canvas.js.map +1 -1
- package/dist-client/modeller/clips.d.ts +23 -6
- package/dist-client/modeller/clips.js +69 -4
- package/dist-client/modeller/clips.js.map +1 -1
- package/dist-client/modeller/data-interface.d.ts +5 -0
- package/dist-client/modeller/data-interface.js +15 -0
- package/dist-client/modeller/data-interface.js.map +1 -1
- package/dist-client/modeller/editor-styles.js +11 -0
- package/dist-client/modeller/editor-styles.js.map +1 -1
- package/dist-client/modeller/editor.d.ts +6 -0
- package/dist-client/modeller/editor.js +35 -11
- package/dist-client/modeller/editor.js.map +1 -1
- package/dist-client/modeller/fasten-form.d.ts +8 -0
- package/dist-client/modeller/fasten-form.js +68 -5
- package/dist-client/modeller/fasten-form.js.map +1 -1
- package/dist-client/modeller/fasten-geometry.d.ts +6 -0
- package/dist-client/modeller/fasten-geometry.js +10 -1
- package/dist-client/modeller/fasten-geometry.js.map +1 -1
- package/dist-client/modeller/figure-cavity-drawing.js +1 -3
- package/dist-client/modeller/figure-cavity-drawing.js.map +1 -1
- package/dist-client/modeller/figure-clips.d.ts +9 -0
- package/dist-client/modeller/figure-clips.js +104 -8
- package/dist-client/modeller/figure-clips.js.map +1 -1
- package/dist-client/modeller/figure-fasten-dialog.js +39 -24
- package/dist-client/modeller/figure-fasten-dialog.js.map +1 -1
- package/dist-client/modeller/figure-fasten-drawing.js +5 -4
- package/dist-client/modeller/figure-fasten-drawing.js.map +1 -1
- package/dist-client/modeller/figure-first-save.js +4 -3
- package/dist-client/modeller/figure-first-save.js.map +1 -1
- package/dist-client/modeller/figure-links.d.ts +9 -0
- package/dist-client/modeller/figure-links.js +89 -35
- package/dist-client/modeller/figure-links.js.map +1 -1
- package/dist-client/modeller/figure-preview.js +48 -4
- package/dist-client/modeller/figure-preview.js.map +1 -1
- package/dist-client/modeller/figure-size-editor.js +7 -3
- package/dist-client/modeller/figure-size-editor.js.map +1 -1
- package/dist-client/modeller/first-save.d.ts +5 -0
- package/dist-client/modeller/first-save.js +7 -0
- package/dist-client/modeller/first-save.js.map +1 -1
- package/dist-client/modeller/focus-on-render.d.ts +2 -0
- package/dist-client/modeller/focus-on-render.js +4 -0
- package/dist-client/modeller/focus-on-render.js.map +1 -0
- package/dist-client/modeller/links.d.ts +1 -1
- package/dist-client/modeller/palette.d.ts +14 -0
- package/dist-client/modeller/palette.js +23 -0
- package/dist-client/modeller/palette.js.map +1 -1
- package/dist-client/modeller/pivot.d.ts +12 -0
- package/dist-client/modeller/pivot.js +59 -0
- package/dist-client/modeller/pivot.js.map +1 -0
- package/dist-client/modeller/product-session.js +6 -2
- package/dist-client/modeller/product-session.js.map +1 -1
- package/dist-client/modeller/size-response.d.ts +6 -0
- package/dist-client/modeller/size-response.js +14 -0
- package/dist-client/modeller/size-response.js.map +1 -1
- package/dist-client/modeller/stage-model.d.ts +17 -3
- package/dist-client/modeller/stage-model.js +44 -6
- package/dist-client/modeller/stage-model.js.map +1 -1
- package/dist-client/route.d.ts +1 -1
- package/dist-client/tsconfig.tsbuildinfo +1 -1
- package/dist-client/types.d.ts +2 -0
- package/dist-client/types.js.map +1 -1
- package/package.json +5 -5
- package/test/browser/editing.check.mjs +6 -5
- package/test/browser/section.check.mjs +21 -0
- package/test/clips.test.ts +49 -4
- package/test/data-motion.test.ts +8 -0
- package/test/fasten-form.test.ts +57 -0
- package/test/fasten-geometry.test.ts +25 -1
- package/test/first-part-on-plane.test.ts +52 -0
- package/test/first-save.test.ts +11 -1
- package/test/pivot.test.ts +57 -0
- package/test/save-landed.test.ts +20 -1
- package/test/size-response.test.ts +10 -2
- package/test/stage-model.test.ts +23 -1
- package/translations/en.json +9 -0
- package/translations/es.json +9 -0
- package/translations/ja.json +9 -0
- package/translations/ko.json +9 -0
- package/translations/ms.json +9 -0
- package/translations/zh.json +9 -0
- package/tutorial/humanoid/README.md +22 -0
- package/tutorial/humanoid/chapters.mjs +247 -0
- package/tutorial/humanoid/encode.mjs +26 -0
- package/tutorial/humanoid/lib.mjs +197 -0
- package/tutorial/humanoid/record.mjs +65 -0
|
@@ -73,6 +73,14 @@ export interface FastenPlan {
|
|
|
73
73
|
axis: Axis;
|
|
74
74
|
edges: boolean;
|
|
75
75
|
}[];
|
|
76
|
+
/**
|
|
77
|
+
* Every axis across the face, the drawing's too: the details ask each by a number as well (review 2026-11-11: a thigh
|
|
78
|
+
* dragged to a pelvis's edge overshot by 47 mm, and dragged back by eye).
|
|
79
|
+
*/
|
|
80
|
+
alignAxes?: {
|
|
81
|
+
axis: Axis;
|
|
82
|
+
edges: boolean;
|
|
83
|
+
}[];
|
|
76
84
|
action?: FigureAuthoringAction;
|
|
77
85
|
/** The face the command would meet, lit on the canvas while it is tried. */
|
|
78
86
|
face?: {
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { FIGURE_FACES, figureFastenKeptGapOf, figureFastenTargetAt, figurePlaneFacingOf, figureSurfaceKeptPlaceOf } from '@hatiolab/figure-model';
|
|
2
2
|
import { faceViewOf, facesAsDrawnOf } from './fasten-geometry.js';
|
|
3
|
-
import { alignOf, alignRowsOf, canFasten, facesOf, fasteningOf, fastenGapOf, hangsFrom, heldBy, mountingPlaneOf, placeKeptOf, surfaceOf } from './links.js';
|
|
3
|
+
import { alignOf, alignAxesOf, alignRowsOf, canFasten, facesOf, fasteningOf, fastenGapOf, hangsFrom, heldBy, mountingPlaneOf, placeKeptOf, surfaceOf } from './links.js';
|
|
4
|
+
import { standsWhereAdded } from './palette.js';
|
|
4
5
|
import { ownerOf } from './fields.js';
|
|
5
6
|
/*
|
|
6
7
|
* A fastening as it is chosen, before it is done: to what, which face, how, where across the face. The fastening window
|
|
@@ -23,11 +24,61 @@ export const freshFasten = () => ({
|
|
|
23
24
|
/** The part's own fastening as a form, or a fresh one: a window opens on what the part has (walk 1, 2026-09-26). */
|
|
24
25
|
export function fastenFormOf(revision, part) {
|
|
25
26
|
const own = fasteningOf(revision, part);
|
|
26
|
-
if (!own || own.atOrigin)
|
|
27
|
-
|
|
27
|
+
if (!own || own.atOrigin) {
|
|
28
|
+
/* A part still where it was added was put nowhere by the author: fastened, it goes on the face, no gap to keep. */
|
|
29
|
+
return addedUnplaced(revision, part) ? { ...freshFasten(), gapFrom: 'pressed' } : freshFasten();
|
|
30
|
+
}
|
|
28
31
|
/* A gap the record works out is the author's; a number is where the part stands, so aiming again keeps it there. */
|
|
29
32
|
return { ...freshFasten(), ...own, gapFrom: own.gapKept !== undefined ? 'typed' : 'kept' };
|
|
30
33
|
}
|
|
34
|
+
/** A part fastened to nothing that still stands where the palette put it: the author has put it nowhere to keep. */
|
|
35
|
+
function addedUnplaced(revision, part) {
|
|
36
|
+
if (fasteningOf(revision, part))
|
|
37
|
+
return false;
|
|
38
|
+
const pose = revision.geometry.find(g => g.id === part)?.pose;
|
|
39
|
+
return standsWhereAdded(pose);
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* The face a part just added starts on when aimed at `target`: the one asked, unless another part is fastened there
|
|
43
|
+
* already -- then the first face of the target nothing is fastened to (review 2026-11-11: a thigh aimed at a pelvis
|
|
44
|
+
* started on its top, where the body stands, and went inside the body until the bottom was chosen). A part the author
|
|
45
|
+
* has placed keeps the face it stands by: a face holds many parts (rollers and a lid on one frame).
|
|
46
|
+
*/
|
|
47
|
+
function freeFaceOf(revision, part, target, asked) {
|
|
48
|
+
const on = (end) => end;
|
|
49
|
+
const joints = revision.asset.joints ?? [];
|
|
50
|
+
const taken = new Set(joints.filter(j => on(j.body0).part === target && on(j.body1).part !== part).map(j => on(j.body0).face));
|
|
51
|
+
/* The face the target itself stands on its own parent by: a thigh hung under a pelvis touches it with its top. */
|
|
52
|
+
let hungBy;
|
|
53
|
+
for (const j of joints)
|
|
54
|
+
if (on(j.body1).part === target && on(j.body0).face && j.facing !== 'flush') {
|
|
55
|
+
hungBy = OPPOSITE[on(j.body0).face];
|
|
56
|
+
taken.add(hungBy);
|
|
57
|
+
}
|
|
58
|
+
/*
|
|
59
|
+
A tall part hung by its side -- an upper arm on a torso -- goes on downward: what is fastened to it starts under its
|
|
60
|
+
bottom end, not on its top beside the shoulder (tutorial run 2026-11-12: a forearm started on the upper arm's top
|
|
61
|
+
and its bottom had to be picked by hand).
|
|
62
|
+
*/
|
|
63
|
+
if (hungBy && FIGURE_FACES[hungBy] !== 'y' && !taken.has('bottom') && tallOf(revision, target))
|
|
64
|
+
return 'bottom';
|
|
65
|
+
if (!taken.has(asked))
|
|
66
|
+
return asked;
|
|
67
|
+
/* The face across from the one taken first: a body on the top, legs under the bottom. */
|
|
68
|
+
const across = OPPOSITE[asked];
|
|
69
|
+
const faces = facesOf(revision.asset, target);
|
|
70
|
+
if (faces.includes(across) && !taken.has(across))
|
|
71
|
+
return across;
|
|
72
|
+
return faces.find(face => !taken.has(face)) ?? asked;
|
|
73
|
+
}
|
|
74
|
+
/** Whether a part as drawn is at least half again as tall as it is wide and deep, read off its own faces. */
|
|
75
|
+
function tallOf(revision, part) {
|
|
76
|
+
const faces = revision.geometry.find(g => g.id === part)?.shape?.faces;
|
|
77
|
+
const span = (lo, hi) => (faces?.[hi] && faces?.[lo] ? Math.abs(faces[hi].at - faces[lo].at) : undefined);
|
|
78
|
+
const [x, y, z] = [span('left', 'right'), span('bottom', 'top'), span('back', 'front')];
|
|
79
|
+
return x !== undefined && y !== undefined && z !== undefined && y >= 1.5 * Math.max(x, z);
|
|
80
|
+
}
|
|
81
|
+
const OPPOSITE = { top: 'bottom', bottom: 'top', left: 'right', right: 'left', front: 'back', back: 'front' };
|
|
31
82
|
/** What a part may be fastened to: every other part that can be, each said whether it would close a loop. */
|
|
32
83
|
export function fastenTargetsOf(revision, part) {
|
|
33
84
|
const asset = revision.asset;
|
|
@@ -69,7 +120,12 @@ export function aimFasten(revision, part, form, to) {
|
|
|
69
120
|
const f = 'plane' in to
|
|
70
121
|
? { ...form, toPlane: true, target: '', facing: form.toPlane ? form.facing : (figurePlaneFacingOf(revision.asset) ?? form.facing) }
|
|
71
122
|
: 'part' in to
|
|
72
|
-
? {
|
|
123
|
+
? {
|
|
124
|
+
...form,
|
|
125
|
+
toPlane: false,
|
|
126
|
+
target: to.part,
|
|
127
|
+
targetFace: to.part !== form.target && addedUnplaced(revision, part) ? freeFaceOf(revision, part, to.part, form.targetFace) : form.targetFace
|
|
128
|
+
}
|
|
73
129
|
: { ...form, targetFace: to.targetFace };
|
|
74
130
|
const theirFaces = f.target ? facesOf(revision.asset, f.target) : FACES;
|
|
75
131
|
const targetFace = (theirFaces.includes(f.targetFace) ? f.targetFace : theirFaces[0]);
|
|
@@ -78,7 +134,13 @@ export function aimFasten(revision, part, form, to) {
|
|
|
78
134
|
: f.target
|
|
79
135
|
? { part: f.target, face: targetFace }
|
|
80
136
|
: undefined;
|
|
81
|
-
|
|
137
|
+
/*
|
|
138
|
+
* A part still where the palette put it has no place of the author's to keep: it goes to the face's centre (review
|
|
139
|
+
* 2026-11-11: a shin added at the origin and aimed at a thigh 85 mm off it was put 85 mm off the thigh's centre; an
|
|
140
|
+
* arm aimed at the body's side stood off the face, out of reach of the drawing).
|
|
141
|
+
*/
|
|
142
|
+
const centred = { align: {}, alignMm: {}, alignInput: {} };
|
|
143
|
+
return { ...f, ...(aim && !addedUnplaced(revision, part) ? placeKeptOf(revision, part, aim) : centred) };
|
|
82
144
|
}
|
|
83
145
|
/** A change the drawing asks: a face, a way, a gap or a place across the face. */
|
|
84
146
|
export function fastenChanged(revision, part, form, change) {
|
|
@@ -173,6 +235,7 @@ function fastenPlanWithout(revision, part, f) {
|
|
|
173
235
|
mode,
|
|
174
236
|
view,
|
|
175
237
|
alignRows: alignRowsOf(asset, aim, view, f.alignInput),
|
|
238
|
+
alignAxes: alignAxesOf(asset, aim),
|
|
176
239
|
action,
|
|
177
240
|
...(f.toPlane ? {} : { face: { part: f.target, face: targetFace } })
|
|
178
241
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fasten-form.js","sourceRoot":"","sources":["../../client/modeller/fasten-form.ts"],"names":[],"mappings":"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","sourcesContent":["import { FIGURE_FACES, figureFastenKeptGapOf, figureFastenTargetAt, figurePlaneFacingOf, figureSurfaceKeptPlaceOf } from '@hatiolab/figure-model'\nimport type { FigureAuthoringAction, FigureFace, FigureSurfacePlace } from '@hatiolab/figure-model'\n\nimport { faceViewOf, facesAsDrawnOf, type FaceView, type FastenMode, type FastenTarget } from './fasten-geometry.js'\nimport type { FastenChange } from './figure-fasten-drawing.js'\nimport {\n alignOf,\n alignRowsOf,\n canFasten,\n facesOf,\n fasteningOf,\n fastenGapOf,\n hangsFrom,\n heldBy,\n mountingPlaneOf,\n placeKeptOf,\n surfaceOf,\n type Alignment,\n type Axis\n} from './links.js'\nimport type { FigureRevision } from './revision.js'\nimport { ownerOf } from './fields.js'\n\n/*\n * A fastening as it is chosen, before it is done: to what, which face, how, where across the face. The fastening window\n * (`figure-fasten-dialog.ts`) holds one and changes it as the author chooses; the attach command is worked out from it\n * only here, so the window, its preview and the panel's 「정렬 고치기」 send the same command for the same choice.\n */\n\nconst FACES = Object.keys(FIGURE_FACES) as FigureFace[]\n\nexport interface FastenForm {\n toPlane: boolean\n target: string\n targetFace: FigureFace\n /** How it meets the face: its near end on it, its far end on it (flush), or its middle (ADR-0140 3.11). */\n facing: FastenMode\n gap: number\n /** The record's gap when it is worked out (a length that follows something): kept until a number is typed. */\n gapKept: unknown\n /**\n * Where the gap came from (ADR-0140 stage 4, 「현재 상태로 붙이기」): `kept` -- the distance the part stands at, worked\n * out again whenever where or how it is fastened changes, so fastening does not move it; `typed` -- the author's\n * number, left as it is; `pressed` -- 0, the part put where the canvas was pressed.\n */\n gapFrom: 'kept' | 'typed' | 'pressed'\n align: Partial<Record<Axis, Alignment>>\n alignMm: Partial<Record<Axis, number>>\n alignInput: Partial<Record<Axis, string>>\n /** On a point of the target's curved surface instead of a face (ADR-0140 3.9): where, as the record says it. */\n surface?: FigureSurfacePlace\n}\n\nexport const freshFasten = (): FastenForm => ({\n toPlane: false,\n target: '',\n targetFace: 'top',\n facing: 'meet',\n gap: 0,\n gapKept: undefined,\n gapFrom: 'kept',\n align: {},\n alignMm: {},\n alignInput: {}\n})\n\n/** The part's own fastening as a form, or a fresh one: a window opens on what the part has (walk 1, 2026-09-26). */\nexport function fastenFormOf(revision: FigureRevision, part: string): FastenForm {\n const own = fasteningOf(revision, part)\n if (!own || own.atOrigin) return freshFasten()\n /* A gap the record works out is the author's; a number is where the part stands, so aiming again keeps it there. */\n return { ...freshFasten(), ...own, gapFrom: own.gapKept !== undefined ? 'typed' : 'kept' } as FastenForm\n}\n\n/** What a part may be fastened to: every other part that can be, each said whether it would close a loop. */\nexport function fastenTargetsOf(revision: FigureRevision, part: string): Array<{ part: string; loops: boolean }> {\n const asset = revision.asset\n return (\n asset.appearance\n .map(look => look.target)\n .filter(one => one !== part && canFasten(asset, one))\n /* Not a part that hangs from this one: fastening a frame to its own roller would close a loop. */\n .map(one => ({ part: one, loops: hangsFrom(asset, one, part) }))\n )\n}\n\n/**\n * The point of a target's curved surface on the side the part stands on now (ADR-0140 3.9): the kernel's\n * (`figureSurfaceKeptPlaceOf`), or, the part standing on its axis, the surface's first point.\n */\nexport function surfaceKeptOf(revision: FigureRevision, part: string, target: string): FigureSurfacePlace | undefined {\n const surface = surfaceOf(revision.asset, target)\n if (!surface) return undefined\n return (\n figureSurfaceKeptPlaceOf(revision.asset, part, target, { ...revision.inputs }) ??\n (surface.form === 'around' ? { around: 0, along: 'centre' } : { toward: { x: 0, y: 1, z: 0 } })\n )\n}\n\n/**\n * A new aim: the plane, another part, another face of the same part, or a point of its curved surface. Where on the\n * face -- or the surface -- is filled in as where the part stands now, so fastening it keeps it there (`placeKeptOf`,\n * `surfaceKeptOf`); the author changes it from there. A part aimed at a sphere, or beside a cylinder's side within its\n * length, is aimed at the surface: it is fastened as it stands (ADR-0140 3.6).\n */\nexport function aimFasten(\n revision: FigureRevision,\n part: string,\n form: FastenForm,\n to: { plane: true } | { part: string } | { targetFace: FigureFace } | { surface: true }\n): FastenForm {\n if ('surface' in to) return { ...form, surface: surfaceKeptOf(revision, part, form.target), align: {}, alignMm: {}, alignInput: {} }\n if ('part' in to) {\n /* Beside its curved surface -- a sphere's anywhere, a cylinder's side within its length -- or with no face at all. */\n const beside = figureSurfaceKeptPlaceOf(revision.asset, part, to.part, { ...revision.inputs })\n const kept = beside ?? (!facesOf(revision.asset, to.part).length ? surfaceKeptOf(revision, part, to.part) : undefined)\n if (kept) return { ...form, toPlane: false, target: to.part, surface: kept, align: {}, alignMm: {}, alignInput: {} }\n }\n form = { ...form, surface: undefined }\n /* Aimed at the plane, it meets it toward the side the placement uses -- below a ceiling -- until the author says (ADR-0140 3.11). */\n const f: FastenForm =\n 'plane' in to\n ? { ...form, toPlane: true, target: '', facing: form.toPlane ? form.facing : (figurePlaneFacingOf(revision.asset) ?? form.facing) }\n : 'part' in to\n ? { ...form, toPlane: false, target: to.part }\n : { ...form, targetFace: to.targetFace }\n const theirFaces = f.target ? facesOf(revision.asset, f.target) : FACES\n const targetFace = (theirFaces.includes(f.targetFace) ? f.targetFace : theirFaces[0]) as FigureFace\n const aim: FastenTarget | undefined = f.toPlane\n ? 'plane'\n : f.target\n ? { part: f.target, face: targetFace }\n : undefined\n return { ...f, ...(aim ? placeKeptOf(revision, part, aim) : { align: {}, alignMm: {}, alignInput: {} }) }\n}\n\n/** A change the drawing asks: a face, a way, a gap or a place across the face. */\nexport function fastenChanged(\n revision: FigureRevision,\n part: string,\n form: FastenForm,\n change: FastenChange\n): FastenForm {\n const f = form\n if ('targetFace' in change) return keptGapOf(revision, part, aimFasten(revision, part, f, { targetFace: change.targetFace as FigureFace }))\n if ('onSurface' in change) return keptGapOf(revision, part, aimFasten(revision, part, f, { surface: true }))\n if ('surface' in change) return keptGapOf(revision, part, { ...f, surface: change.surface })\n if ('mode' in change) return keptGapOf(revision, part, { ...f, facing: change.mode })\n if ('gap' in change) return { ...f, gap: change.gap, gapKept: undefined, gapFrom: 'typed' }\n return {\n ...f,\n align: { ...f.align, [change.axis]: change.how },\n alignMm: change.how === 'mm' ? { ...f.alignMm, [change.axis]: change.mm ?? 0 } : f.alignMm\n }\n}\n\n/**\n * The form with the gap that keeps the part where it stands (ADR-0140 stage 4, user 2026-10-20 「현재 상태로 붙이기」):\n * figure-model's `figureFastenKeptGapOf` for what it is aimed at and how it meets it. A gap the author typed, or the 0 a\n * canvas press puts, is left as it is. Nothing aimed at yet, the form is as it was.\n */\nexport function keptGapOf(revision: FigureRevision, part: string, form: FastenForm): FastenForm {\n if (form.gapFrom !== 'kept') return form\n const asset = revision.asset\n const theirFaces = form.target ? facesOf(asset, form.target) : FACES\n const targetFace = (theirFaces.includes(form.targetFace) ? form.targetFace : theirFaces[0]) as FigureFace\n const planeWay = figurePlaneFacingOf(asset)\n const mode: FastenMode = form.toPlane ? (mountingPlaneOf(asset).facings.includes(form.facing) ? form.facing : (planeWay ?? 'meet')) : form.facing\n const to = form.toPlane\n ? ('plane' as const)\n : form.target && form.surface && surfaceOf(asset, form.target)\n ? { part: form.target, surface: form.surface }\n : form.target\n ? { part: form.target, face: targetFace }\n : undefined\n if (!to) return form\n return { ...form, gap: figureFastenKeptGapOf(asset, part, to, mode, { ...revision.inputs }), gapKept: undefined }\n}\n\n/** What a form comes to: the face aimed at, the way, the drawing of the face and the command. */\nexport interface FastenPlan {\n /** Nothing is aimed at until a part or the plane is chosen. */\n aim?: FastenTarget\n theirFaces: string[]\n targetFace: FigureFace\n mode: FastenMode\n view?: FaceView\n /** The axes across the face asked in rows: where the drawing cannot set the place. */\n alignRows: { axis: Axis; edges: boolean }[]\n action?: FigureAuthoringAction\n /** The face the command would meet, lit on the canvas while it is tried. */\n face?: { part: string; face: string }\n /** On a point of the target's curved surface: which surface, about which axis, and where (ADR-0140 3.9). */\n surface?: { form: 'around' | 'toward'; axis: Axis; place: FigureSurfacePlace }\n /** The target's own face at each of the drawing's places, as the target is drawn (\\`facesAsDrawnOf\\`). */\n drawnFaces?: Record<FigureFace, FigureFace>\n}\n\nexport function fastenPlanOf(revision: FigureRevision, part: string, f: FastenForm): FastenPlan {\n const plan = fastenPlanWithout(revision, part, f)\n return f.target && !f.toPlane ? { ...plan, drawnFaces: facesAsDrawnOf(revision, f.target) } : plan\n}\n\nfunction fastenPlanWithout(revision: FigureRevision, part: string, f: FastenForm): FastenPlan {\n const asset = revision.asset\n const theirFaces = f.target ? facesOf(asset, f.target) : FACES\n const targetFace = (theirFaces.includes(f.targetFace) ? f.targetFace : theirFaces[0]) as FigureFace\n const aim: FastenTarget | undefined = f.toPlane\n ? 'plane'\n : f.target\n ? { part: f.target, face: targetFace }\n : undefined\n /* The plane takes a part standing on it or hanging below it, a wall only one standing out of it (ADR-0140 3.11). */\n const planeWay = figurePlaneFacingOf(asset)\n const mode: FastenMode = f.toPlane ? (mountingPlaneOf(asset).facings.includes(f.facing) ? f.facing : (planeWay ?? 'meet')) : f.facing\n const surface = !f.toPlane && f.target && f.surface ? surfaceOf(asset, f.target) : undefined\n if (surface) {\n /* On the surface: where is the surface's own words, so no alignment goes with it (ADR-0140 3.9). */\n const action = {\n kind: 'attach',\n part,\n to: { part: f.target, surface: f.surface },\n facing: mode,\n ...fastenGapOf(f),\n replace: !!heldBy(asset, part)\n } as FigureAuthoringAction\n return { theirFaces, targetFace, mode, alignRows: [], action, surface: { ...surface, place: f.surface! } }\n }\n if (!aim) return { theirFaces, targetFace, mode, alignRows: [] }\n const align = alignOf(asset, aim, f.align, f.alignMm, f.alignInput)\n const view = faceViewOf(revision, part, aim, mode)\n const action = {\n kind: 'attach',\n part,\n to: f.toPlane ? { plane: 'mounting-plane' } : { part: f.target, face: targetFace },\n /* On the plane the kernel takes the placement's way when none is said: only another way is said. */\n ...(f.toPlane ? (mode === planeWay ? {} : { facing: mode }) : { facing: mode }),\n ...fastenGapOf(f),\n ...(align ? { align } : {}),\n replace: !!heldBy(asset, part)\n } as FigureAuthoringAction\n return {\n aim,\n theirFaces,\n targetFace,\n mode,\n view,\n alignRows: alignRowsOf(asset, aim, view, f.alignInput),\n action,\n ...(f.toPlane ? {} : { face: { part: f.target, face: targetFace } })\n }\n}\n\ntype Say = (key: string, params?: Record<string, string>) => string\n\n/** 「bin의 윗면에 올려놓기」: what the fastening is, in one line -- the part is the one the window is open on, not named again. */\nexport function fastenSentenceOf(\n form: FastenForm,\n plan: FastenPlan,\n planeWord: string,\n say: Say\n): string {\n const where = plan.surface ? say('figure.label.surface-' + plan.surface.form) : say('figure.label.face-' + plan.targetFace)\n const to = form.toPlane ? planeWord : `${form.target}의 ${where}`\n return say(`figure.text.fasten-sentence-${plan.mode}`, { to })\n}\n\n/**\n * What the folded details hold that is not their default, said while folded; nothing for the default. The gap's default\n * is the one it starts at -- the distance the part stands at, or 0 where the canvas was pressed -- so only a number typed\n * is said.\n */\nexport function fastenDetailWordsOf(form: FastenForm, say: Say): string[] {\n return [\n ...(form.gapKept !== undefined\n ? [say('figure.text.fasten-summary-gap-worked-out')]\n : form.gapFrom === 'typed' && form.gap\n ? [say('figure.text.fasten-summary-gap', { mm: String(form.gap) })]\n : [])\n ]\n}\n\n/**\n * A part pressed on the canvas while the window is open (ADR-0140 stage 4): aimed at, on the face or the point pressed,\n * its middle where it was pressed -- the kernel's reading of the press (`figureFastenTargetAt`), the point and normal brought into that part's own\n * frame by the pose its body is drawn at (`at.id`, a row's copy too). The part itself, one hanging from it, or one with\n * nothing to fasten to is not aimed at; a press on a curve there is no fastening to aims at the part alone. Each says\n * why, by its words' key.\n */\n/* Put where the canvas was pressed: on the face or the surface there, with no gap (ADR-0140 stage 4). */\nconst PRESSED = { gap: 0, gapKept: undefined, gapFrom: 'pressed' as const }\n\nexport function aimFastenAt(\n revision: FigureRevision,\n part: string,\n form: FastenForm,\n at: { id: string; point?: readonly number[]; normal?: readonly number[] }\n): { form?: FastenForm; note?: 'aim-self' | 'aim-cannot' | 'target-would-loop' | 'aim-not-here'; part: string } {\n const target = ownerOf(at.id)\n const offered = fastenTargetsOf(revision, part).find(t => t.part === target)\n if (target === part) return { note: 'aim-self', part: target }\n if (!offered) return { note: 'aim-cannot', part: target }\n if (offered.loops) return { note: 'target-would-loop', part: target }\n const aimed = aimFasten(revision, part, form, { part: target })\n const pose = (revision.geometry as Array<{ id: string; pose?: { r: number[][]; t: number[] } }>).find(g => g.id === at.id)?.pose\n if (!pose || !at.point || !at.normal) return { form: aimed, part: target }\n /* Into the part's own frame: rᵀ (p − t), and the normal by rᵀ. */\n const own = (v: readonly number[], from: readonly number[] = [0, 0, 0]) => [0, 1, 2].map(c => [0, 1, 2].reduce((sum, i) => sum + pose.r[i]![c]! * (v[i]! - from[i]!), 0))\n const lands = figureFastenTargetAt(revision.asset, target, own(at.point, pose.t), own(at.normal), { ...revision.inputs })\n if ('face' in lands) {\n /* On the face where it was pressed, as a point of a curved surface is: its middle there. */\n const onFace = aimFasten(revision, part, { ...aimed, surface: undefined }, { targetFace: lands.face as FigureFace })\n const at = lands.at as Partial<Record<Axis, number>>\n return { form: { ...onFace, ...PRESSED, align: Object.fromEntries(Object.keys(at).map(a => [a, 'mm'])) as FastenForm['align'], alignMm: { ...at }, alignInput: {} }, part: target }\n }\n if ('surface' in lands) return { form: { ...aimed, ...PRESSED, toPlane: false, target, surface: lands.surface, align: {}, alignMm: {}, alignInput: {} }, part: target }\n return { form: aimed, note: 'aim-not-here', part: target }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"fasten-form.js","sourceRoot":"","sources":["../../client/modeller/fasten-form.ts"],"names":[],"mappings":"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","sourcesContent":["import { FIGURE_FACES, figureFastenKeptGapOf, figureFastenTargetAt, figurePlaneFacingOf, figureSurfaceKeptPlaceOf } from '@hatiolab/figure-model'\nimport type { FigureAuthoringAction, FigureFace, FigureSurfacePlace } from '@hatiolab/figure-model'\n\nimport { faceViewOf, facesAsDrawnOf, type FaceView, type FastenMode, type FastenTarget } from './fasten-geometry.js'\nimport type { FastenChange } from './figure-fasten-drawing.js'\nimport {\n alignOf,\n alignAxesOf,\n alignRowsOf,\n canFasten,\n facesOf,\n fasteningOf,\n fastenGapOf,\n hangsFrom,\n heldBy,\n mountingPlaneOf,\n placeKeptOf,\n surfaceOf,\n type Alignment,\n type Axis\n} from './links.js'\nimport type { FigureRevision } from './revision.js'\nimport { standsWhereAdded } from './palette.js'\nimport { ownerOf } from './fields.js'\n\n/*\n * A fastening as it is chosen, before it is done: to what, which face, how, where across the face. The fastening window\n * (`figure-fasten-dialog.ts`) holds one and changes it as the author chooses; the attach command is worked out from it\n * only here, so the window, its preview and the panel's 「정렬 고치기」 send the same command for the same choice.\n */\n\nconst FACES = Object.keys(FIGURE_FACES) as FigureFace[]\n\nexport interface FastenForm {\n toPlane: boolean\n target: string\n targetFace: FigureFace\n /** How it meets the face: its near end on it, its far end on it (flush), or its middle (ADR-0140 3.11). */\n facing: FastenMode\n gap: number\n /** The record's gap when it is worked out (a length that follows something): kept until a number is typed. */\n gapKept: unknown\n /**\n * Where the gap came from (ADR-0140 stage 4, 「현재 상태로 붙이기」): `kept` -- the distance the part stands at, worked\n * out again whenever where or how it is fastened changes, so fastening does not move it; `typed` -- the author's\n * number, left as it is; `pressed` -- 0, the part put where the canvas was pressed.\n */\n gapFrom: 'kept' | 'typed' | 'pressed'\n align: Partial<Record<Axis, Alignment>>\n alignMm: Partial<Record<Axis, number>>\n alignInput: Partial<Record<Axis, string>>\n /** On a point of the target's curved surface instead of a face (ADR-0140 3.9): where, as the record says it. */\n surface?: FigureSurfacePlace\n}\n\nexport const freshFasten = (): FastenForm => ({\n toPlane: false,\n target: '',\n targetFace: 'top',\n facing: 'meet',\n gap: 0,\n gapKept: undefined,\n gapFrom: 'kept',\n align: {},\n alignMm: {},\n alignInput: {}\n})\n\n/** The part's own fastening as a form, or a fresh one: a window opens on what the part has (walk 1, 2026-09-26). */\nexport function fastenFormOf(revision: FigureRevision, part: string): FastenForm {\n const own = fasteningOf(revision, part)\n if (!own || own.atOrigin) {\n /* A part still where it was added was put nowhere by the author: fastened, it goes on the face, no gap to keep. */\n return addedUnplaced(revision, part) ? { ...freshFasten(), gapFrom: 'pressed' } : freshFasten()\n }\n /* A gap the record works out is the author's; a number is where the part stands, so aiming again keeps it there. */\n return { ...freshFasten(), ...own, gapFrom: own.gapKept !== undefined ? 'typed' : 'kept' } as FastenForm\n}\n\n/** A part fastened to nothing that still stands where the palette put it: the author has put it nowhere to keep. */\nfunction addedUnplaced(revision: FigureRevision, part: string): boolean {\n if (fasteningOf(revision, part)) return false\n const pose = (revision.geometry.find(g => (g as { id: string }).id === part) as { pose?: { r: number[][]; t: number[] } } | undefined)?.pose\n return standsWhereAdded(pose)\n}\n\n/**\n * The face a part just added starts on when aimed at `target`: the one asked, unless another part is fastened there\n * already -- then the first face of the target nothing is fastened to (review 2026-11-11: a thigh aimed at a pelvis\n * started on its top, where the body stands, and went inside the body until the bottom was chosen). A part the author\n * has placed keeps the face it stands by: a face holds many parts (rollers and a lid on one frame).\n */\nfunction freeFaceOf(revision: FigureRevision, part: string, target: string, asked: FigureFace): FigureFace {\n const on = (end: unknown) => end as { part?: string; face?: string }\n const joints = revision.asset.joints ?? []\n const taken = new Set(joints.filter(j => on(j.body0).part === target && on(j.body1).part !== part).map(j => on(j.body0).face))\n /* The face the target itself stands on its own parent by: a thigh hung under a pelvis touches it with its top. */\n let hungBy: FigureFace | undefined\n for (const j of joints)\n if (on(j.body1).part === target && on(j.body0).face && (j as { facing?: string }).facing !== 'flush') {\n hungBy = OPPOSITE[on(j.body0).face as FigureFace]\n taken.add(hungBy)\n }\n /*\n A tall part hung by its side -- an upper arm on a torso -- goes on downward: what is fastened to it starts under its\n bottom end, not on its top beside the shoulder (tutorial run 2026-11-12: a forearm started on the upper arm's top\n and its bottom had to be picked by hand).\n */\n if (hungBy && FIGURE_FACES[hungBy] !== 'y' && !taken.has('bottom') && tallOf(revision, target)) return 'bottom'\n if (!taken.has(asked)) return asked\n /* The face across from the one taken first: a body on the top, legs under the bottom. */\n const across = OPPOSITE[asked]\n const faces = facesOf(revision.asset, target)\n if (faces.includes(across) && !taken.has(across)) return across\n return (faces.find(face => !taken.has(face)) as FigureFace | undefined) ?? asked\n}\n\n/** Whether a part as drawn is at least half again as tall as it is wide and deep, read off its own faces. */\nfunction tallOf(revision: FigureRevision, part: string): boolean {\n const faces = (revision.geometry.find(g => (g as { id: string }).id === part) as { shape?: { faces?: Record<string, { at: number }> } } | undefined)?.shape?.faces\n const span = (lo: string, hi: string) => (faces?.[hi] && faces?.[lo] ? Math.abs(faces[hi]!.at - faces[lo]!.at) : undefined)\n const [x, y, z] = [span('left', 'right'), span('bottom', 'top'), span('back', 'front')]\n return x !== undefined && y !== undefined && z !== undefined && y >= 1.5 * Math.max(x, z)\n}\n\nconst OPPOSITE: Record<FigureFace, FigureFace> = { top: 'bottom', bottom: 'top', left: 'right', right: 'left', front: 'back', back: 'front' }\n\n/** What a part may be fastened to: every other part that can be, each said whether it would close a loop. */\nexport function fastenTargetsOf(revision: FigureRevision, part: string): Array<{ part: string; loops: boolean }> {\n const asset = revision.asset\n return (\n asset.appearance\n .map(look => look.target)\n .filter(one => one !== part && canFasten(asset, one))\n /* Not a part that hangs from this one: fastening a frame to its own roller would close a loop. */\n .map(one => ({ part: one, loops: hangsFrom(asset, one, part) }))\n )\n}\n\n/**\n * The point of a target's curved surface on the side the part stands on now (ADR-0140 3.9): the kernel's\n * (`figureSurfaceKeptPlaceOf`), or, the part standing on its axis, the surface's first point.\n */\nexport function surfaceKeptOf(revision: FigureRevision, part: string, target: string): FigureSurfacePlace | undefined {\n const surface = surfaceOf(revision.asset, target)\n if (!surface) return undefined\n return (\n figureSurfaceKeptPlaceOf(revision.asset, part, target, { ...revision.inputs }) ??\n (surface.form === 'around' ? { around: 0, along: 'centre' } : { toward: { x: 0, y: 1, z: 0 } })\n )\n}\n\n/**\n * A new aim: the plane, another part, another face of the same part, or a point of its curved surface. Where on the\n * face -- or the surface -- is filled in as where the part stands now, so fastening it keeps it there (`placeKeptOf`,\n * `surfaceKeptOf`); the author changes it from there. A part aimed at a sphere, or beside a cylinder's side within its\n * length, is aimed at the surface: it is fastened as it stands (ADR-0140 3.6).\n */\nexport function aimFasten(\n revision: FigureRevision,\n part: string,\n form: FastenForm,\n to: { plane: true } | { part: string } | { targetFace: FigureFace } | { surface: true }\n): FastenForm {\n if ('surface' in to) return { ...form, surface: surfaceKeptOf(revision, part, form.target), align: {}, alignMm: {}, alignInput: {} }\n if ('part' in to) {\n /* Beside its curved surface -- a sphere's anywhere, a cylinder's side within its length -- or with no face at all. */\n const beside = figureSurfaceKeptPlaceOf(revision.asset, part, to.part, { ...revision.inputs })\n const kept = beside ?? (!facesOf(revision.asset, to.part).length ? surfaceKeptOf(revision, part, to.part) : undefined)\n if (kept) return { ...form, toPlane: false, target: to.part, surface: kept, align: {}, alignMm: {}, alignInput: {} }\n }\n form = { ...form, surface: undefined }\n /* Aimed at the plane, it meets it toward the side the placement uses -- below a ceiling -- until the author says (ADR-0140 3.11). */\n const f: FastenForm =\n 'plane' in to\n ? { ...form, toPlane: true, target: '', facing: form.toPlane ? form.facing : (figurePlaneFacingOf(revision.asset) ?? form.facing) }\n : 'part' in to\n ? {\n ...form,\n toPlane: false,\n target: to.part,\n targetFace: to.part !== form.target && addedUnplaced(revision, part) ? freeFaceOf(revision, part, to.part, form.targetFace) : form.targetFace\n }\n : { ...form, targetFace: to.targetFace }\n const theirFaces = f.target ? facesOf(revision.asset, f.target) : FACES\n const targetFace = (theirFaces.includes(f.targetFace) ? f.targetFace : theirFaces[0]) as FigureFace\n const aim: FastenTarget | undefined = f.toPlane\n ? 'plane'\n : f.target\n ? { part: f.target, face: targetFace }\n : undefined\n /*\n * A part still where the palette put it has no place of the author's to keep: it goes to the face's centre (review\n * 2026-11-11: a shin added at the origin and aimed at a thigh 85 mm off it was put 85 mm off the thigh's centre; an\n * arm aimed at the body's side stood off the face, out of reach of the drawing).\n */\n const centred = { align: {}, alignMm: {}, alignInput: {} }\n return { ...f, ...(aim && !addedUnplaced(revision, part) ? placeKeptOf(revision, part, aim) : centred) }\n}\n\n/** A change the drawing asks: a face, a way, a gap or a place across the face. */\nexport function fastenChanged(\n revision: FigureRevision,\n part: string,\n form: FastenForm,\n change: FastenChange\n): FastenForm {\n const f = form\n if ('targetFace' in change) return keptGapOf(revision, part, aimFasten(revision, part, f, { targetFace: change.targetFace as FigureFace }))\n if ('onSurface' in change) return keptGapOf(revision, part, aimFasten(revision, part, f, { surface: true }))\n if ('surface' in change) return keptGapOf(revision, part, { ...f, surface: change.surface })\n if ('mode' in change) return keptGapOf(revision, part, { ...f, facing: change.mode })\n if ('gap' in change) return { ...f, gap: change.gap, gapKept: undefined, gapFrom: 'typed' }\n return {\n ...f,\n align: { ...f.align, [change.axis]: change.how },\n alignMm: change.how === 'mm' ? { ...f.alignMm, [change.axis]: change.mm ?? 0 } : f.alignMm\n }\n}\n\n/**\n * The form with the gap that keeps the part where it stands (ADR-0140 stage 4, user 2026-10-20 「현재 상태로 붙이기」):\n * figure-model's `figureFastenKeptGapOf` for what it is aimed at and how it meets it. A gap the author typed, or the 0 a\n * canvas press puts, is left as it is. Nothing aimed at yet, the form is as it was.\n */\nexport function keptGapOf(revision: FigureRevision, part: string, form: FastenForm): FastenForm {\n if (form.gapFrom !== 'kept') return form\n const asset = revision.asset\n const theirFaces = form.target ? facesOf(asset, form.target) : FACES\n const targetFace = (theirFaces.includes(form.targetFace) ? form.targetFace : theirFaces[0]) as FigureFace\n const planeWay = figurePlaneFacingOf(asset)\n const mode: FastenMode = form.toPlane ? (mountingPlaneOf(asset).facings.includes(form.facing) ? form.facing : (planeWay ?? 'meet')) : form.facing\n const to = form.toPlane\n ? ('plane' as const)\n : form.target && form.surface && surfaceOf(asset, form.target)\n ? { part: form.target, surface: form.surface }\n : form.target\n ? { part: form.target, face: targetFace }\n : undefined\n if (!to) return form\n return { ...form, gap: figureFastenKeptGapOf(asset, part, to, mode, { ...revision.inputs }), gapKept: undefined }\n}\n\n/** What a form comes to: the face aimed at, the way, the drawing of the face and the command. */\nexport interface FastenPlan {\n /** Nothing is aimed at until a part or the plane is chosen. */\n aim?: FastenTarget\n theirFaces: string[]\n targetFace: FigureFace\n mode: FastenMode\n view?: FaceView\n /** The axes across the face asked in rows: where the drawing cannot set the place. */\n alignRows: { axis: Axis; edges: boolean }[]\n /**\n * Every axis across the face, the drawing's too: the details ask each by a number as well (review 2026-11-11: a thigh\n * dragged to a pelvis's edge overshot by 47 mm, and dragged back by eye).\n */\n alignAxes?: { axis: Axis; edges: boolean }[]\n action?: FigureAuthoringAction\n /** The face the command would meet, lit on the canvas while it is tried. */\n face?: { part: string; face: string }\n /** On a point of the target's curved surface: which surface, about which axis, and where (ADR-0140 3.9). */\n surface?: { form: 'around' | 'toward'; axis: Axis; place: FigureSurfacePlace }\n /** The target's own face at each of the drawing's places, as the target is drawn (\\`facesAsDrawnOf\\`). */\n drawnFaces?: Record<FigureFace, FigureFace>\n}\n\nexport function fastenPlanOf(revision: FigureRevision, part: string, f: FastenForm): FastenPlan {\n const plan = fastenPlanWithout(revision, part, f)\n return f.target && !f.toPlane ? { ...plan, drawnFaces: facesAsDrawnOf(revision, f.target) } : plan\n}\n\nfunction fastenPlanWithout(revision: FigureRevision, part: string, f: FastenForm): FastenPlan {\n const asset = revision.asset\n const theirFaces = f.target ? facesOf(asset, f.target) : FACES\n const targetFace = (theirFaces.includes(f.targetFace) ? f.targetFace : theirFaces[0]) as FigureFace\n const aim: FastenTarget | undefined = f.toPlane\n ? 'plane'\n : f.target\n ? { part: f.target, face: targetFace }\n : undefined\n /* The plane takes a part standing on it or hanging below it, a wall only one standing out of it (ADR-0140 3.11). */\n const planeWay = figurePlaneFacingOf(asset)\n const mode: FastenMode = f.toPlane ? (mountingPlaneOf(asset).facings.includes(f.facing) ? f.facing : (planeWay ?? 'meet')) : f.facing\n const surface = !f.toPlane && f.target && f.surface ? surfaceOf(asset, f.target) : undefined\n if (surface) {\n /* On the surface: where is the surface's own words, so no alignment goes with it (ADR-0140 3.9). */\n const action = {\n kind: 'attach',\n part,\n to: { part: f.target, surface: f.surface },\n facing: mode,\n ...fastenGapOf(f),\n replace: !!heldBy(asset, part)\n } as FigureAuthoringAction\n return { theirFaces, targetFace, mode, alignRows: [], action, surface: { ...surface, place: f.surface! } }\n }\n if (!aim) return { theirFaces, targetFace, mode, alignRows: [] }\n const align = alignOf(asset, aim, f.align, f.alignMm, f.alignInput)\n const view = faceViewOf(revision, part, aim, mode)\n const action = {\n kind: 'attach',\n part,\n to: f.toPlane ? { plane: 'mounting-plane' } : { part: f.target, face: targetFace },\n /* On the plane the kernel takes the placement's way when none is said: only another way is said. */\n ...(f.toPlane ? (mode === planeWay ? {} : { facing: mode }) : { facing: mode }),\n ...fastenGapOf(f),\n ...(align ? { align } : {}),\n replace: !!heldBy(asset, part)\n } as FigureAuthoringAction\n return {\n aim,\n theirFaces,\n targetFace,\n mode,\n view,\n alignRows: alignRowsOf(asset, aim, view, f.alignInput),\n alignAxes: alignAxesOf(asset, aim),\n action,\n ...(f.toPlane ? {} : { face: { part: f.target, face: targetFace } })\n }\n}\n\ntype Say = (key: string, params?: Record<string, string>) => string\n\n/** 「bin의 윗면에 올려놓기」: what the fastening is, in one line -- the part is the one the window is open on, not named again. */\nexport function fastenSentenceOf(\n form: FastenForm,\n plan: FastenPlan,\n planeWord: string,\n say: Say\n): string {\n const where = plan.surface ? say('figure.label.surface-' + plan.surface.form) : say('figure.label.face-' + plan.targetFace)\n const to = form.toPlane ? planeWord : `${form.target}의 ${where}`\n return say(`figure.text.fasten-sentence-${plan.mode}`, { to })\n}\n\n/**\n * What the folded details hold that is not their default, said while folded; nothing for the default. The gap's default\n * is the one it starts at -- the distance the part stands at, or 0 where the canvas was pressed -- so only a number typed\n * is said.\n */\nexport function fastenDetailWordsOf(form: FastenForm, say: Say): string[] {\n return [\n ...(form.gapKept !== undefined\n ? [say('figure.text.fasten-summary-gap-worked-out')]\n : form.gapFrom === 'typed' && form.gap\n ? [say('figure.text.fasten-summary-gap', { mm: String(form.gap) })]\n : [])\n ]\n}\n\n/**\n * A part pressed on the canvas while the window is open (ADR-0140 stage 4): aimed at, on the face or the point pressed,\n * its middle where it was pressed -- the kernel's reading of the press (`figureFastenTargetAt`), the point and normal brought into that part's own\n * frame by the pose its body is drawn at (`at.id`, a row's copy too). The part itself, one hanging from it, or one with\n * nothing to fasten to is not aimed at; a press on a curve there is no fastening to aims at the part alone. Each says\n * why, by its words' key.\n */\n/* Put where the canvas was pressed: on the face or the surface there, with no gap (ADR-0140 stage 4). */\nconst PRESSED = { gap: 0, gapKept: undefined, gapFrom: 'pressed' as const }\n\nexport function aimFastenAt(\n revision: FigureRevision,\n part: string,\n form: FastenForm,\n at: { id: string; point?: readonly number[]; normal?: readonly number[] }\n): { form?: FastenForm; note?: 'aim-self' | 'aim-cannot' | 'target-would-loop' | 'aim-not-here'; part: string } {\n const target = ownerOf(at.id)\n const offered = fastenTargetsOf(revision, part).find(t => t.part === target)\n if (target === part) return { note: 'aim-self', part: target }\n if (!offered) return { note: 'aim-cannot', part: target }\n if (offered.loops) return { note: 'target-would-loop', part: target }\n const aimed = aimFasten(revision, part, form, { part: target })\n const pose = (revision.geometry as Array<{ id: string; pose?: { r: number[][]; t: number[] } }>).find(g => g.id === at.id)?.pose\n if (!pose || !at.point || !at.normal) return { form: aimed, part: target }\n /* Into the part's own frame: rᵀ (p − t), and the normal by rᵀ. */\n const own = (v: readonly number[], from: readonly number[] = [0, 0, 0]) => [0, 1, 2].map(c => [0, 1, 2].reduce((sum, i) => sum + pose.r[i]![c]! * (v[i]! - from[i]!), 0))\n const lands = figureFastenTargetAt(revision.asset, target, own(at.point, pose.t), own(at.normal), { ...revision.inputs })\n if ('face' in lands) {\n /* On the face where it was pressed, as a point of a curved surface is: its middle there. */\n const onFace = aimFasten(revision, part, { ...aimed, surface: undefined }, { targetFace: lands.face as FigureFace })\n const at = lands.at as Partial<Record<Axis, number>>\n return { form: { ...onFace, ...PRESSED, align: Object.fromEntries(Object.keys(at).map(a => [a, 'mm'])) as FastenForm['align'], alignMm: { ...at }, alignInput: {} }, part: target }\n }\n if ('surface' in lands) return { form: { ...aimed, ...PRESSED, toPlane: false, target, surface: lands.surface, align: {}, alignMm: {}, alignInput: {} }, part: target }\n return { form: aimed, note: 'aim-not-here', part: target }\n}\n"]}
|
|
@@ -108,4 +108,10 @@ export declare function fastenLabelsOf(face: {
|
|
|
108
108
|
inside: boolean;
|
|
109
109
|
};
|
|
110
110
|
};
|
|
111
|
+
/**
|
|
112
|
+
* How much of an axis the face drawing shows, mm: room around the face for the part to go past its edges by about half
|
|
113
|
+
* itself, and for a part bigger than the face lined up with one of its edges (a mast flush with a low body's bottom) to
|
|
114
|
+
* show whole; a plane with no size, three parts wide.
|
|
115
|
+
*/
|
|
116
|
+
export declare function drawingSpanOf(face: number | undefined, part: number): number;
|
|
111
117
|
export {};
|
|
@@ -71,7 +71,8 @@ export function alignmentAt(d, face, part, edges, catchMm) {
|
|
|
71
71
|
[-inside, 'min'],
|
|
72
72
|
[inside, 'max']
|
|
73
73
|
])
|
|
74
|
-
|
|
74
|
+
/* Level with an edge whatever the sizes: a part bigger than the face (a mast on a low body) lines up with it too. */
|
|
75
|
+
if (Math.abs(d - at) <= catchMm && inside !== 0)
|
|
75
76
|
return edges ? { how, caught: 'inside' } : { how: 'mm', mm: Math.round(at), caught: 'inside' };
|
|
76
77
|
for (const at of [-outside, outside])
|
|
77
78
|
if (Math.abs(d - at) <= catchMm)
|
|
@@ -147,4 +148,12 @@ export function fastenLabelsOf(face, part, partName, height) {
|
|
|
147
148
|
return { face: facePlace, part: { x: part.x + part.w / 2, y: edge + 14, inside: false } };
|
|
148
149
|
return { face: facePlace, part: { x: part.x + part.w / 2, y: below <= height - 20 ? below : part.y - 5, inside: false } };
|
|
149
150
|
}
|
|
151
|
+
/**
|
|
152
|
+
* How much of an axis the face drawing shows, mm: room around the face for the part to go past its edges by about half
|
|
153
|
+
* itself, and for a part bigger than the face lined up with one of its edges (a mast flush with a low body's bottom) to
|
|
154
|
+
* show whole; a plane with no size, three parts wide.
|
|
155
|
+
*/
|
|
156
|
+
export function drawingSpanOf(face, part) {
|
|
157
|
+
return face !== undefined ? Math.max(face + part, 2 * part - face) : part * 3;
|
|
158
|
+
}
|
|
150
159
|
//# sourceMappingURL=fasten-geometry.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fasten-geometry.js","sourceRoot":"","sources":["../../client/modeller/fasten-geometry.ts"],"names":[],"mappings":"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","sourcesContent":["import { FIGURE_FACES, figureFaceInsideAlignOf, figureFaceMeasureOf, figureFaceOverhangAt, figureFastenPlaceOf } from '@hatiolab/figure-model'\nimport type { FigureAsset, FigureFace, FigureFaceMeasure, FigureFacing, FigureFastenAlignment } from '@hatiolab/figure-model'\n\nimport { alignAxesOf, type Alignment } from './links.js'\nimport type { FigureRevision } from './revision.js'\n\n/*\n * What the 붙이기 drawing reads (user 2026-10-01): the face a part is fastened to, seen from above, and where the part\n * lies on it. A fastening is chosen by the target's face and how (올려놓기 · 같은 면에 맞추기 · 가운데를 면에); the part\n * meets it by its real shape in the pose it has, by no face of its own (ADR-0140 3.2). What is measured -- the face,\n * the part's extent across it, how far it comes past and whether what touches is on it -- is the kernel's\n * (`figureFaceMeasureOf`, 3.8); this only draws it.\n */\n\ntype Axis = 'x' | 'y' | 'z'\nexport type FastenMode = FigureFacing\nexport type FastenTarget = { part: string; face: string } | 'plane'\n\n/* Which way each of the six faces looks, along its axis, in a part's own frame. */\nconst OUTWARD: Record<FigureFace, number> = { left: -1, right: 1, bottom: -1, top: 1, back: -1, front: 1 }\nconst SIX = Object.keys(OUTWARD) as FigureFace[]\n\n/**\n * The target's own face that stands at each of the drawing's six places as the part is drawn (robot dog, 2026-11-03):\n * a face is named in its part's own frame, so a cylinder laid on its side has its 「아래」 on the side, and the box drawn\n * upright showed the name where the face is not. Each place -- up, down, right, left, toward the eye, away -- shows the\n * own face whose outward normal, turned by the part's pose, points most that way. Unturned, each is itself.\n */\nexport function facesAsDrawnOf(revision: FigureRevision, target: string): Record<FigureFace, FigureFace> {\n const drawn = (revision.geometry as Array<{ id: string; pose?: { r: number[][] } }>).find(g => g.id === target)?.pose?.r\n const same = Object.fromEntries(SIX.map(f => [f, f])) as Record<FigureFace, FigureFace>\n if (!drawn) return same\n const index = { x: 0, y: 1, z: 2 } as const\n /* World direction of an own face: its column of the pose, outward. */\n const world = (f: FigureFace) => [0, 1, 2].map(i => OUTWARD[f] * drawn[i]![index[FIGURE_FACES[f] as Axis]]!)\n const along = (place: FigureFace) => [0, 1, 2].map(i => (i === index[FIGURE_FACES[place] as Axis] ? OUTWARD[place] : 0))\n const dot = (a: number[], b: number[]) => a.reduce((sum, v, i) => sum + v * b[i]!, 0)\n return Object.fromEntries(SIX.map(place => [place, SIX.reduce((best, f) => (dot(world(f), along(place)) > dot(world(best), along(place)) ? f : best))])) as Record<FigureFace, FigureFace>\n}\n\n/**\n * The face seen from above: its two axes across (as the form's alignment names them), the face's size on each as a\n * fastening lines up to it -- none for a plane with no declared size -- the part's real extent on each, whether its\n * edges can be lined up with, and the kernel's measure the drawing asks again as the part is moved.\n */\nexport interface FaceView {\n axes: [Axis, Axis]\n face: Partial<Record<Axis, number>>\n part: Record<Axis, number>\n edges: Record<Axis, boolean>\n measure: FigureFaceMeasure\n}\n\nexport function faceViewOf(revision: FigureRevision, part: string, target: FastenTarget, facing: FastenMode): FaceView | undefined {\n const measure = (() => {\n try {\n return figureFaceMeasureOf(revision.asset, part, revision.inputs, { on: target, facing })\n } catch {\n return undefined\n }\n })()\n if (!measure) return undefined\n const across = alignAxesOf(revision.asset, target)\n const face: Partial<Record<Axis, number>> = {}\n for (const a of measure.axes) {\n const e = measure.edges[a]\n if (e) face[a] = e.hi - e.lo\n }\n const extent = (a: Axis) => measure.extent[a].hi - measure.extent[a].lo\n return {\n axes: measure.axes,\n face,\n part: { x: extent('x'), y: extent('y'), z: extent('z') },\n edges: Object.fromEntries(measure.axes.map(a => [a, !!across.find(o => o.axis === a)?.edges])) as Record<Axis, boolean>,\n measure\n }\n}\n\n/**\n * Where the part's centre is from the face's centre along one axis, for the way it is aligned there: the kernel's\n * `figureFastenPlaceOf` (ADR-0140 D2), the form's distances -- typed, or a share of the size read as millimetres -- as\n * a distance, a position field's as the centre.\n */\nexport function offsetOf(how: Alignment | undefined, mm: number | undefined, face: number | undefined, part: number): number {\n const align = how === 'mm' || how === 'share' ? { mm: mm ?? 0 } : how === 'min' || how === 'max' || how === 'centre' ? how : undefined\n return figureFastenPlaceOf({ align: { x: align }, face: { x: face }, part: { x: part } }).x!\n}\n\n/**\n * A place dropped on the face, as the form's alignment: caught at the centre, at an edge from inside (level with it:\n * `min` / `max`, where the edges can be lined up with), or at an edge from outside (touching it, as a distance), when\n * within `catchMm`; anywhere else a distance off centre, whole millimetres.\n */\nexport function alignmentAt(d: number, face: number | undefined, part: number, edges: boolean, catchMm: number): { how: Alignment; mm?: number; caught?: 'centre' | 'inside' | 'outside' } {\n if (Math.abs(d) <= catchMm) return { how: 'centre', caught: 'centre' }\n if (face !== undefined) {\n const inside = (face - part) / 2,\n outside = (face + part) / 2\n for (const [at, how] of [\n [-inside, 'min'],\n [inside, 'max']\n ] as const)\n if (Math.abs(d - at) <= catchMm && inside > 0) return edges ? { how, caught: 'inside' } : { how: 'mm', mm: Math.round(at), caught: 'inside' }\n for (const at of [-outside, outside]) if (Math.abs(d - at) <= catchMm) return { how: 'mm', mm: Math.round(at), caught: 'outside' }\n }\n return { how: 'mm', mm: Math.round(d) }\n}\n\n/** The form's alignment on each axis across the face, in the kernel's words: a typed or shared distance as millimetres. */\nfunction kernelAlignOf(view: FaceView, align: Partial<Record<Axis, Alignment>>, alignMm: Partial<Record<Axis, number>>): Partial<Record<Axis, FigureFastenAlignment>> {\n const out: Partial<Record<Axis, FigureFastenAlignment>> = {}\n for (const a of view.axes) {\n const how = align[a] ?? 'centre'\n out[a] = how === 'mm' || how === 'share' ? { mm: alignMm[a] ?? 0 } : how === 'min' || how === 'max' ? how : 'centre'\n }\n return out\n}\n\n/**\n * The alignment that brings the part inside the face, for 정렬·간격 고치기: the kernel's least move\n * (`figureFaceInsideAlignOf`), in the form's words. `inside` when nothing of it is past an edge: what is out is something\n * fastened on it. `unmeasured` when the face has no size to measure against.\n */\nexport function insideAlignmentOf(\n view: FaceView | undefined,\n align: Partial<Record<Axis, Alignment>>,\n alignMm: Partial<Record<Axis, number>>\n): { align: Partial<Record<Axis, Alignment>>; alignMm: Partial<Record<Axis, number>>; moved: Axis[] } | { cannot: 'inside' | 'unmeasured' } {\n if (!view) return { cannot: 'unmeasured' }\n const fix = figureFaceInsideAlignOf(view.measure, kernelAlignOf(view, align, alignMm), view.edges)\n if ('cannot' in fix) return fix\n const next = { align: { ...align }, alignMm: { ...alignMm }, moved: fix.moved as Axis[] }\n for (const a of fix.moved as Axis[]) {\n const how = fix.align[a]\n if (how && typeof how === 'object') ((next.align[a] = 'mm'), (next.alignMm[a] = how.mm))\n else if (how) next.align[a] = how\n }\n return next\n}\n\n/**\n * How far the part comes past the face's edges, per side, whether any of it lies over the face, and whether what\n * touches the face is on it -- with its middle `at` from the face's middle: the kernel's (`figureFaceOverhangAt`).\n */\nexport function overhangOf(view: FaceView, at: Record<Axis, number>): { touching: boolean; contact: 'on' | 'off' | 'unknown'; sides: Array<{ axis: Axis; side: 'low' | 'high'; mm: number }> } {\n const o = figureFaceOverhangAt(view.measure, Object.fromEntries(view.axes.map(a => [a, { mm: at[a] }])))\n return { touching: o.over, contact: o.contact, sides: o.sides as Array<{ axis: Axis; side: 'low' | 'high'; mm: number }> }\n}\n\n/** Whether the part turns about a joint: then 가운데를 면에 is offered -- a roller spinning in place. */\nexport const turnsInPlace = (asset: FigureAsset, part: string) =>\n (asset.joints ?? []).some(j => j.body1.part === part && ((j.motion ?? []).some(a => a.type === 'revolute') || j.origin?.facing === 'centre'))\n\n/**\n * How the face lies on the screen: X across when it is one of the face's axes, else Z; the other down the screen -- up\n * for Y, which rises, so a front face is seen as it stands and not upside down.\n */\nexport function screenOf(axes: readonly [Axis, Axis]): { h: Axis; v: Axis; sign: Record<Axis, 1 | -1> } {\n const h = axes.includes('x') ? 'x' : 'z'\n const v = axes.find(a => a !== h)!\n return { h, v, sign: { x: 1, y: 1, z: 1, [v]: v === 'y' ? -1 : 1 } as Record<Axis, 1 | -1> }\n}\n\n/**\n * Where the fastening drawing writes its two names so neither lies over the other (user 2026-10-16: 「roller」 over the\n * roller's thin bar, and 「frame 윗면 2000 × 600」 cut by it). The face's name stands above the face, inside its top edge\n * only when the face fills the drawing. The part's name stands in the part when the part is wide and tall enough for it,\n * else just under it -- above it when the drawing ends first. Under a part as tall as the face, just under it is the\n * face's own edge, and the name lay on that line (2026-10-18, the roller in the fastening window): it goes under the edge.\n * Widths are estimated: 7 px a letter at 11-12 px; a line of it stands 11 px over its baseline and 3 under.\n */\nexport function fastenLabelsOf(\n face: { x: number; y: number; w: number; h: number },\n part: { x: number; y: number; w: number; h: number },\n partName: string,\n height: number\n): { face: { x: number; y: number }; part: { x: number; y: number; inside: boolean } } {\n const facePlace = face.y >= 16 ? { x: face.x, y: face.y - 5 } : { x: face.x + 4, y: face.y + 14 }\n const fits = part.w >= partName.length * 7 + 8 && part.h >= 16\n if (fits) return { face: facePlace, part: { x: part.x + part.w / 2, y: part.y + part.h / 2 + 4, inside: true } }\n const below = part.y + part.h + 14\n const edge = face.y + face.h\n if (below - 11 < edge + 2 && below + 3 > edge - 2 && edge + 14 <= height - 4) return { face: facePlace, part: { x: part.x + part.w / 2, y: edge + 14, inside: false } }\n return { face: facePlace, part: { x: part.x + part.w / 2, y: below <= height - 20 ? below : part.y - 5, inside: false } }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"fasten-geometry.js","sourceRoot":"","sources":["../../client/modeller/fasten-geometry.ts"],"names":[],"mappings":"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","sourcesContent":["import { FIGURE_FACES, figureFaceInsideAlignOf, figureFaceMeasureOf, figureFaceOverhangAt, figureFastenPlaceOf } from '@hatiolab/figure-model'\nimport type { FigureAsset, FigureFace, FigureFaceMeasure, FigureFacing, FigureFastenAlignment } from '@hatiolab/figure-model'\n\nimport { alignAxesOf, type Alignment } from './links.js'\nimport type { FigureRevision } from './revision.js'\n\n/*\n * What the 붙이기 drawing reads (user 2026-10-01): the face a part is fastened to, seen from above, and where the part\n * lies on it. A fastening is chosen by the target's face and how (올려놓기 · 같은 면에 맞추기 · 가운데를 면에); the part\n * meets it by its real shape in the pose it has, by no face of its own (ADR-0140 3.2). What is measured -- the face,\n * the part's extent across it, how far it comes past and whether what touches is on it -- is the kernel's\n * (`figureFaceMeasureOf`, 3.8); this only draws it.\n */\n\ntype Axis = 'x' | 'y' | 'z'\nexport type FastenMode = FigureFacing\nexport type FastenTarget = { part: string; face: string } | 'plane'\n\n/* Which way each of the six faces looks, along its axis, in a part's own frame. */\nconst OUTWARD: Record<FigureFace, number> = { left: -1, right: 1, bottom: -1, top: 1, back: -1, front: 1 }\nconst SIX = Object.keys(OUTWARD) as FigureFace[]\n\n/**\n * The target's own face that stands at each of the drawing's six places as the part is drawn (robot dog, 2026-11-03):\n * a face is named in its part's own frame, so a cylinder laid on its side has its 「아래」 on the side, and the box drawn\n * upright showed the name where the face is not. Each place -- up, down, right, left, toward the eye, away -- shows the\n * own face whose outward normal, turned by the part's pose, points most that way. Unturned, each is itself.\n */\nexport function facesAsDrawnOf(revision: FigureRevision, target: string): Record<FigureFace, FigureFace> {\n const drawn = (revision.geometry as Array<{ id: string; pose?: { r: number[][] } }>).find(g => g.id === target)?.pose?.r\n const same = Object.fromEntries(SIX.map(f => [f, f])) as Record<FigureFace, FigureFace>\n if (!drawn) return same\n const index = { x: 0, y: 1, z: 2 } as const\n /* World direction of an own face: its column of the pose, outward. */\n const world = (f: FigureFace) => [0, 1, 2].map(i => OUTWARD[f] * drawn[i]![index[FIGURE_FACES[f] as Axis]]!)\n const along = (place: FigureFace) => [0, 1, 2].map(i => (i === index[FIGURE_FACES[place] as Axis] ? OUTWARD[place] : 0))\n const dot = (a: number[], b: number[]) => a.reduce((sum, v, i) => sum + v * b[i]!, 0)\n return Object.fromEntries(SIX.map(place => [place, SIX.reduce((best, f) => (dot(world(f), along(place)) > dot(world(best), along(place)) ? f : best))])) as Record<FigureFace, FigureFace>\n}\n\n/**\n * The face seen from above: its two axes across (as the form's alignment names them), the face's size on each as a\n * fastening lines up to it -- none for a plane with no declared size -- the part's real extent on each, whether its\n * edges can be lined up with, and the kernel's measure the drawing asks again as the part is moved.\n */\nexport interface FaceView {\n axes: [Axis, Axis]\n face: Partial<Record<Axis, number>>\n part: Record<Axis, number>\n edges: Record<Axis, boolean>\n measure: FigureFaceMeasure\n}\n\nexport function faceViewOf(revision: FigureRevision, part: string, target: FastenTarget, facing: FastenMode): FaceView | undefined {\n const measure = (() => {\n try {\n return figureFaceMeasureOf(revision.asset, part, revision.inputs, { on: target, facing })\n } catch {\n return undefined\n }\n })()\n if (!measure) return undefined\n const across = alignAxesOf(revision.asset, target)\n const face: Partial<Record<Axis, number>> = {}\n for (const a of measure.axes) {\n const e = measure.edges[a]\n if (e) face[a] = e.hi - e.lo\n }\n const extent = (a: Axis) => measure.extent[a].hi - measure.extent[a].lo\n return {\n axes: measure.axes,\n face,\n part: { x: extent('x'), y: extent('y'), z: extent('z') },\n edges: Object.fromEntries(measure.axes.map(a => [a, !!across.find(o => o.axis === a)?.edges])) as Record<Axis, boolean>,\n measure\n }\n}\n\n/**\n * Where the part's centre is from the face's centre along one axis, for the way it is aligned there: the kernel's\n * `figureFastenPlaceOf` (ADR-0140 D2), the form's distances -- typed, or a share of the size read as millimetres -- as\n * a distance, a position field's as the centre.\n */\nexport function offsetOf(how: Alignment | undefined, mm: number | undefined, face: number | undefined, part: number): number {\n const align = how === 'mm' || how === 'share' ? { mm: mm ?? 0 } : how === 'min' || how === 'max' || how === 'centre' ? how : undefined\n return figureFastenPlaceOf({ align: { x: align }, face: { x: face }, part: { x: part } }).x!\n}\n\n/**\n * A place dropped on the face, as the form's alignment: caught at the centre, at an edge from inside (level with it:\n * `min` / `max`, where the edges can be lined up with), or at an edge from outside (touching it, as a distance), when\n * within `catchMm`; anywhere else a distance off centre, whole millimetres.\n */\nexport function alignmentAt(d: number, face: number | undefined, part: number, edges: boolean, catchMm: number): { how: Alignment; mm?: number; caught?: 'centre' | 'inside' | 'outside' } {\n if (Math.abs(d) <= catchMm) return { how: 'centre', caught: 'centre' }\n if (face !== undefined) {\n const inside = (face - part) / 2,\n outside = (face + part) / 2\n for (const [at, how] of [\n [-inside, 'min'],\n [inside, 'max']\n ] as const)\n /* Level with an edge whatever the sizes: a part bigger than the face (a mast on a low body) lines up with it too. */\n if (Math.abs(d - at) <= catchMm && inside !== 0) return edges ? { how, caught: 'inside' } : { how: 'mm', mm: Math.round(at), caught: 'inside' }\n for (const at of [-outside, outside]) if (Math.abs(d - at) <= catchMm) return { how: 'mm', mm: Math.round(at), caught: 'outside' }\n }\n return { how: 'mm', mm: Math.round(d) }\n}\n\n/** The form's alignment on each axis across the face, in the kernel's words: a typed or shared distance as millimetres. */\nfunction kernelAlignOf(view: FaceView, align: Partial<Record<Axis, Alignment>>, alignMm: Partial<Record<Axis, number>>): Partial<Record<Axis, FigureFastenAlignment>> {\n const out: Partial<Record<Axis, FigureFastenAlignment>> = {}\n for (const a of view.axes) {\n const how = align[a] ?? 'centre'\n out[a] = how === 'mm' || how === 'share' ? { mm: alignMm[a] ?? 0 } : how === 'min' || how === 'max' ? how : 'centre'\n }\n return out\n}\n\n/**\n * The alignment that brings the part inside the face, for 정렬·간격 고치기: the kernel's least move\n * (`figureFaceInsideAlignOf`), in the form's words. `inside` when nothing of it is past an edge: what is out is something\n * fastened on it. `unmeasured` when the face has no size to measure against.\n */\nexport function insideAlignmentOf(\n view: FaceView | undefined,\n align: Partial<Record<Axis, Alignment>>,\n alignMm: Partial<Record<Axis, number>>\n): { align: Partial<Record<Axis, Alignment>>; alignMm: Partial<Record<Axis, number>>; moved: Axis[] } | { cannot: 'inside' | 'unmeasured' } {\n if (!view) return { cannot: 'unmeasured' }\n const fix = figureFaceInsideAlignOf(view.measure, kernelAlignOf(view, align, alignMm), view.edges)\n if ('cannot' in fix) return fix\n const next = { align: { ...align }, alignMm: { ...alignMm }, moved: fix.moved as Axis[] }\n for (const a of fix.moved as Axis[]) {\n const how = fix.align[a]\n if (how && typeof how === 'object') ((next.align[a] = 'mm'), (next.alignMm[a] = how.mm))\n else if (how) next.align[a] = how\n }\n return next\n}\n\n/**\n * How far the part comes past the face's edges, per side, whether any of it lies over the face, and whether what\n * touches the face is on it -- with its middle `at` from the face's middle: the kernel's (`figureFaceOverhangAt`).\n */\nexport function overhangOf(view: FaceView, at: Record<Axis, number>): { touching: boolean; contact: 'on' | 'off' | 'unknown'; sides: Array<{ axis: Axis; side: 'low' | 'high'; mm: number }> } {\n const o = figureFaceOverhangAt(view.measure, Object.fromEntries(view.axes.map(a => [a, { mm: at[a] }])))\n return { touching: o.over, contact: o.contact, sides: o.sides as Array<{ axis: Axis; side: 'low' | 'high'; mm: number }> }\n}\n\n/** Whether the part turns about a joint: then 가운데를 면에 is offered -- a roller spinning in place. */\nexport const turnsInPlace = (asset: FigureAsset, part: string) =>\n (asset.joints ?? []).some(j => j.body1.part === part && ((j.motion ?? []).some(a => a.type === 'revolute') || j.origin?.facing === 'centre'))\n\n/**\n * How the face lies on the screen: X across when it is one of the face's axes, else Z; the other down the screen -- up\n * for Y, which rises, so a front face is seen as it stands and not upside down.\n */\nexport function screenOf(axes: readonly [Axis, Axis]): { h: Axis; v: Axis; sign: Record<Axis, 1 | -1> } {\n const h = axes.includes('x') ? 'x' : 'z'\n const v = axes.find(a => a !== h)!\n return { h, v, sign: { x: 1, y: 1, z: 1, [v]: v === 'y' ? -1 : 1 } as Record<Axis, 1 | -1> }\n}\n\n/**\n * Where the fastening drawing writes its two names so neither lies over the other (user 2026-10-16: 「roller」 over the\n * roller's thin bar, and 「frame 윗면 2000 × 600」 cut by it). The face's name stands above the face, inside its top edge\n * only when the face fills the drawing. The part's name stands in the part when the part is wide and tall enough for it,\n * else just under it -- above it when the drawing ends first. Under a part as tall as the face, just under it is the\n * face's own edge, and the name lay on that line (2026-10-18, the roller in the fastening window): it goes under the edge.\n * Widths are estimated: 7 px a letter at 11-12 px; a line of it stands 11 px over its baseline and 3 under.\n */\nexport function fastenLabelsOf(\n face: { x: number; y: number; w: number; h: number },\n part: { x: number; y: number; w: number; h: number },\n partName: string,\n height: number\n): { face: { x: number; y: number }; part: { x: number; y: number; inside: boolean } } {\n const facePlace = face.y >= 16 ? { x: face.x, y: face.y - 5 } : { x: face.x + 4, y: face.y + 14 }\n const fits = part.w >= partName.length * 7 + 8 && part.h >= 16\n if (fits) return { face: facePlace, part: { x: part.x + part.w / 2, y: part.y + part.h / 2 + 4, inside: true } }\n const below = part.y + part.h + 14\n const edge = face.y + face.h\n if (below - 11 < edge + 2 && below + 3 > edge - 2 && edge + 14 <= height - 4) return { face: facePlace, part: { x: part.x + part.w / 2, y: edge + 14, inside: false } }\n return { face: facePlace, part: { x: part.x + part.w / 2, y: below <= height - 20 ? below : part.y - 5, inside: false } }\n}\n\n/**\n * How much of an axis the face drawing shows, mm: room around the face for the part to go past its edges by about half\n * itself, and for a part bigger than the face lined up with one of its edges (a mast flush with a low body's bottom) to\n * show whole; a plane with no size, three parts wide.\n */\nexport function drawingSpanOf(face: number | undefined, part: number): number {\n return face !== undefined ? Math.max(face + part, 2 * part - face) : part * 3\n}\n"]}
|
|
@@ -1,12 +1,10 @@
|
|
|
1
1
|
import { __decorate, __metadata } from "tslib";
|
|
2
2
|
import { css, html, LitElement, nothing, svg } from 'lit';
|
|
3
3
|
import { customElement, property, state } from 'lit/decorators.js';
|
|
4
|
-
import { ref } from 'lit/directives/ref.js';
|
|
5
4
|
import { i18next, localize } from '@operato/i18n';
|
|
6
5
|
import { figureCavitySectionOf } from '@hatiolab/figure-model';
|
|
6
|
+
import { focusOnRender } from './focus-on-render.js';
|
|
7
7
|
import { cavityRefusalWordsOf, cavityWorkingOf, END_FACE, endToggled, mm, SIDE_FACE, wallDragged } from './section-controls.js';
|
|
8
|
-
/** A field opened by a press takes the keys at once. */
|
|
9
|
-
const focusOnRender = () => ref(el => el && requestAnimationFrame(() => el.select()));
|
|
10
8
|
/** How the section is laid on the screen, by the axis it is pushed along: across to the right, then down. */
|
|
11
9
|
const SCREEN = { y: ['x', 'z'], x: ['z', 'y'], z: ['x', 'y'] };
|
|
12
10
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"figure-cavity-drawing.js","sourceRoot":"","sources":["../../client/modeller/figure-cavity-drawing.ts"],"names":[],"mappings":"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","sourcesContent":["import { css, html, LitElement, nothing, svg } from 'lit'\nimport { customElement, property, state } from 'lit/decorators.js'\nimport { ref } from 'lit/directives/ref.js'\n\nimport { i18next, localize } from '@operato/i18n'\nimport { figureCavitySectionOf } from '@hatiolab/figure-model'\nimport type { FigureAuthoringAction, FigureCavityRequest, FigureEvaluatedShape, FigureSection } from '@hatiolab/figure-model'\nimport { cavityRefusalWordsOf, cavityWorkingOf, END_FACE, endToggled, mm, SIDE_FACE, wallDragged } from './section-controls.js'\n\ntype Axis = 'x' | 'y' | 'z'\n\n/** A field opened by a press takes the keys at once. */\nconst focusOnRender = () => ref(el => el && requestAnimationFrame(() => (el as HTMLInputElement).select()))\ntype End = 'start' | 'end'\ntype Body = { id: string; shape: FigureEvaluatedShape }\n\n/** How the section is laid on the screen, by the axis it is pushed along: across to the right, then down. */\nconst SCREEN: Record<Axis, [Axis, Axis]> = { y: ['x', 'z'], x: ['z', 'y'], z: ['x', 'y'] }\n\n/**\n * 속 공간 그림 — the inside of a pushed part drawn, and edited by drawing (user 2026-10-01: 「이해와 편집이 직관적이지 않다」).\n *\n * Seen along the push, the section and its inside: a handle in the middle of each wall is dragged to its thickness,\n * every wall together unless 면마다 벽 is on. Cut along the push, the walls and the two ends: an end pressed opens or\n * closes it, a closed end's inner line is dragged to its thickness. While dragging, the figure behind shows what the\n * inside makes (`command-live`); letting go sends one `set-cavity`. What the kernel would refuse is drawn in the error\n * colour and said, by the kernel's own check, and is not sent.\n */\n@customElement('figure-cavity-drawing')\nexport class FigureCavityDrawing extends localize(i18next)(LitElement) {\n static styles = css`\n :host {\n display: grid;\n gap: 6px;\n }\n svg {\n width: 100%;\n display: block;\n touch-action: none;\n user-select: none;\n }\n svg text {\n font: inherit;\n }\n small[refusal] {\n color: var(--md-sys-color-error);\n }\n div[pane] {\n position: relative;\n }\n div[pane] input {\n position: absolute;\n width: 64px;\n transform: translate(-50%, -50%);\n font: inherit;\n }\n text[typed] {\n cursor: text;\n text-decoration: underline dotted;\n }\n `\n\n @property({ attribute: false }) body?: Body\n @property({ type: Boolean }) locked = false\n /** Walls one per side: a handle moves its own wall only. */\n @property({ type: Boolean }) perSide = false\n\n /** What is being dragged, and the inside it makes; undefined when nothing is. */\n @state() private working?: ReturnType<typeof cavityWorkingOf>\n @state() private refusal = ''\n private dragging: { kind: 'wall'; side: string } | { kind: 'end'; end: End } | null = null\n /** A number pressed to be typed: which, and where on its picture (percent of the picture's box). */\n @state() private typing?: ({ kind: 'wall'; side: string } | { kind: 'end'; end: End }) & { x: number; y: number; pane: 'top' | 'side'; value: number }\n private pressedAt = 0\n\n private get now() {\n return this.working ?? (this.body ? cavityWorkingOf(this.body.shape) : undefined)\n }\n\n private request(w: NonNullable<ReturnType<typeof cavityWorkingOf>>): FigureCavityRequest {\n return { wall: { ...w.wall }, start: w.start, end: w.end }\n }\n\n private action(w: NonNullable<ReturnType<typeof cavityWorkingOf>>): FigureAuthoringAction {\n return { kind: 'set-cavity', part: this.body!.id, cavity: this.request(w) }\n }\n\n /** What the kernel would refuse, in words; for one side's wall, the most that side can be with the opposite kept. */\n private judge(w: NonNullable<ReturnType<typeof cavityWorkingOf>>, side?: string): string {\n const words = cavityRefusalWordsOf(this.body!.shape, w, this.perSide, side)\n return words ? i18next.t(words.key, words.params) : ''\n }\n\n /** The working inside while dragging: drawn, judged, and previewed behind when the kernel would take it. */\n private hold(w: NonNullable<ReturnType<typeof cavityWorkingOf>>, side?: string) {\n this.working = w\n this.refusal = this.judge(w, side)\n this.emit('command-live', this.refusal ? null : this.action(w))\n }\n\n private release() {\n const w = this.working\n this.dragging = null\n this.working = undefined\n if (!w) return\n /* Refused: nothing is sent, and the reason stays said until the next drag -- letting go must not look like taking it. */\n if (this.refusal) {\n this.emit('command-live', null)\n return\n }\n this.emit('command', this.action(w))\n }\n\n private emit(name: 'command' | 'command-live', action: FigureAuthoringAction | null) {\n this.dispatchEvent(new CustomEvent(name, { detail: { action }, bubbles: true, composed: true }))\n }\n\n private point(ev: PointerEvent, el: SVGSVGElement) {\n const pt = el.createSVGPoint()\n pt.x = ev.clientX\n pt.y = ev.clientY\n return pt.matrixTransform(el.getScreenCTM()!.inverse())\n }\n\n render() {\n const e = this.body?.shape.extrusion\n const w = this.now\n if (!e || !w || (e.section.kind !== 'rectangle' && e.section.kind !== 'ellipse')) return nothing\n return html`<div pane>${this.top(e, w)}${this.typing?.pane === 'top' ? this.renderTyping() : nothing}</div>\n <div pane>${this.side(e, w)}${this.typing?.pane === 'side' ? this.renderTyping() : nothing}</div>\n ${this.refusal ? html`<small refusal role=\"alert\">${this.refusal}</small>` : nothing}`\n }\n\n /** Press a number, type it, Enter: the same one set-cavity a drag sends; Esc or leaving puts it back. */\n private type(ev: PointerEvent, what: { kind: 'wall'; side: string } | { kind: 'end'; end: End }, pane: 'top' | 'side', value: number) {\n if (this.locked) return\n ev.stopPropagation()\n const svgEl = (ev.target as Element).closest('svg')!\n const box = svgEl.getBoundingClientRect()\n this.refusal = ''\n this.typing = { ...what, pane, value, x: ((ev.clientX - box.left) / box.width) * 100, y: ((ev.clientY - box.top) / box.height) * 100 }\n }\n\n private renderTyping() {\n const t = this.typing!\n return html`<input type=\"number\" step=\"1\" min=\"1\" .value=${String(t.value)} style=${`left:${t.x}%;top:${t.y}%`}\n aria-label=${t.kind === 'wall' ? i18next.t('figure.label.section-wall') : i18next.t('figure.label.face-' + END_FACE(this.body!.shape.extrusion!.axis, t.end))}\n @keydown=${(ev: KeyboardEvent) => {\n ev.stopPropagation()\n if (ev.key === 'Escape') this.typing = undefined\n if (ev.key !== 'Enter') return\n const value = Number((ev.target as HTMLInputElement).value)\n this.typing = undefined\n if (!(Number.isFinite(value) && value > 0)) return\n const now = this.now!\n const next = t.kind === 'wall' ? { ...now, wall: wallDragged(now.wall, t.side, value, this.perSide) } : { ...now, [t.end]: { closed: Math.round(value) } }\n this.refusal = this.judge(next, t.kind === 'wall' ? t.side : undefined)\n if (!this.refusal) this.emit('command', this.action(next))\n }}\n @blur=${() => (this.typing = undefined)}\n ${focusOnRender()} />`\n }\n\n /** Seen along the push: the section, its inside and a handle on each wall. */\n private top(e: NonNullable<FigureEvaluatedShape['extrusion']>, w: NonNullable<ReturnType<typeof cavityWorkingOf>>) {\n const [h, v] = SCREEN[e.axis]\n const s = e.section\n const across = (a: Axis) => (s.kind === 'rectangle' ? s.size[a]! : 2 * (s as { radius: Record<string, number> }).radius[a]!)\n const W = 300,\n H = 170,\n pad = 26\n /* Wider room left and right: a wall's number stands outside the section there. */\n const k = Math.min((W - 2 * (pad + 10)) / across(h), (H - 2 * pad) / across(v))\n const ox = W / 2,\n oy = H / 2\n const inside = figureCavitySectionOf(s as FigureSection, e.axis, w.wall)\n const bad = !!this.refusal || !('section' in inside)\n const shape = (sec: FigureSection, c: Partial<Record<Axis, number>>, attrs: string) => {\n const cx = ox + (c[h] ?? 0) * k,\n cy = oy + (c[v] ?? 0) * k\n if (sec.kind === 'ellipse') return svg`<ellipse cx=${cx} cy=${cy} rx=${sec.radius[h]! * k} ry=${sec.radius[v]! * k} style=${attrs} />`\n const r = sec as { size: Record<string, number>; corner?: Record<string, number> }\n return svg`<rect x=${cx - (r.size[h]! * k) / 2} y=${cy - (r.size[v]! * k) / 2} width=${r.size[h]! * k} height=${r.size[v]! * k}\n rx=${(r.corner?.[h] ?? 0) * k} ry=${(r.corner?.[v] ?? 0) * k} style=${attrs} />`\n }\n const half = { [h]: (across(h) * k) / 2, [v]: (across(v) * k) / 2 } as Record<Axis, number>\n /* Each wall's handle sits on the inside's edge, half way along it; the value is the wall's own. */\n const handles = [`${h}-`, `${h}+`, `${v}-`, `${v}+`].map(side => {\n const a = side[0] as Axis,\n low = side[1] === '-'\n const sign = low ? -1 : 1\n const edge = sign * (half[a] - w.wall[side]! * k)\n /* The two handles across a narrow inside would stand on each other: then each steps aside, the low one first. */\n const room = 2 * half[a] - (w.wall[`${a}-`]! + w.wall[`${a}+`]!) * k\n const aside = room < 16 ? sign * 9 : 0\n const x = a === h ? ox + edge : ox + aside,\n y = a === v ? oy + edge : oy + aside\n /*\n The number stands just past the section's outer edge on its own side, so the opposite wall's never meets it\n however thin the walls or shallow the section (2026-10-02: at 70 mm deep the two walls' numbers lay on each other).\n */\n const tx = a === h ? ox + sign * (half[a] + 5) : ox,\n ty = a === v ? oy + sign * (half[a] + (low ? 5 : 13)) : oy + 4\n return svg`<g wall=${side} style=${`cursor:${a === h ? 'ew-resize' : 'ns-resize'}`}\n @pointerdown=${(ev: PointerEvent) => this.grab(ev, { kind: 'wall', side })}>\n <rect x=${x - 6} y=${y - 6} width=\"12\" height=\"12\" rx=\"2\" style=\"fill:var(--md-sys-color-surface);stroke:var(--md-sys-color-primary);stroke-width:1.5\" />\n <text typed x=${tx} y=${ty} font-size=\"11\" text-anchor=${a === h ? (low ? 'end' : 'start') : 'middle'} style=\"fill:var(--md-sys-color-on-surface)\"\n @pointerdown=${(ev: PointerEvent) => this.type(ev, { kind: 'wall', side }, 'top', w.wall[side]!)}>${mm(w.wall[side]!)}</text>\n <title>${i18next.t('figure.label.face-' + SIDE_FACE[side])} ${i18next.t('figure.label.section-wall')}</title>\n </g>`\n })\n return svg`<svg viewBox=${`0 0 ${W} ${H}`} role=\"img\" aria-label=${i18next.t('figure.label.section-cavity-top')}\n @pointermove=${(ev: PointerEvent) => this.drag(ev, e, k, ox, oy, half)}\n @pointerup=${() => this.release()} @pointercancel=${() => this.release()}>\n ${shape(s as FigureSection, {}, 'fill:var(--md-sys-color-primary-container);stroke:var(--md-sys-color-primary);stroke-width:1.5')}\n ${'section' in inside\n ? shape(inside.section, inside.centre, `fill:var(--md-sys-color-surface);stroke:${bad ? 'var(--md-sys-color-error)' : 'var(--md-sys-color-primary)'};stroke-width:1.2;stroke-dasharray:4 3`)\n : nothing}\n ${this.locked ? nothing : handles}\n </svg>`\n }\n\n /** Cut along the push: the walls across the first plane axis, and the two ends -- pressed to open or close. */\n private side(e: NonNullable<FigureEvaluatedShape['extrusion']>, w: NonNullable<ReturnType<typeof cavityWorkingOf>>) {\n const [h] = SCREEN[e.axis]\n const s = e.section\n const width = s.kind === 'rectangle' ? s.size[h]! : 2 * (s as { radius: Record<string, number> }).radius[h]!\n const length = e.end - e.start\n const W = 300,\n H = 170,\n padX = 40,\n padY = 26\n const k = Math.min((W - 2 * padX) / width, (H - 2 * padY) / length)\n const x0 = W / 2 - (width * k) / 2,\n x1 = W / 2 + (width * k) / 2,\n yTop = H / 2 - (length * k) / 2,\n yBot = H / 2 + (length * k) / 2\n const wl = w.wall[`${h}-`]! * k,\n wr = w.wall[`${h}+`]! * k\n const thick = (end: End) => (w[end] === 'open' ? 0 : (w[end] as { closed: number }).closed * k)\n /* The push's start is drawn at the bottom: a tote stands on its floor. */\n const floor = thick('start'),\n lid = thick('end')\n const fill = 'fill:var(--md-sys-color-primary-container);stroke:var(--md-sys-color-primary);stroke-width:1.2'\n const endZone = (end: End, y: number, t: number) => {\n const open = w[end] === 'open'\n const words = open\n ? i18next.t('figure.label.section-end-open')\n : `${i18next.t('figure.label.section-end-closed')} ${mm((w[end] as { closed: number }).closed)}`\n const label = `${i18next.t('figure.label.face-' + END_FACE(e.axis, end))}: ${words}`\n const inner = end === 'start' ? y - t : y + t\n return svg`<g end=${end} style=${`cursor:${open ? 'pointer' : 'ns-resize'}`}\n @pointerdown=${(ev: PointerEvent) => this.grab(ev, { kind: 'end', end })}>\n <rect x=${x0 + wl} y=${Math.min(y, inner) - 8} width=${x1 - x0 - wl - wr} height=${Math.abs(t) + 16} style=\"fill:transparent\" />\n ${open ? svg`<line x1=${x0 + wl} y1=${y} x2=${x1 - wr} y2=${y} style=\"stroke:var(--md-sys-color-outline);stroke-dasharray:3 3\" />` : nothing}\n <text ?typed=${!open} x=${W / 2} y=${end === 'start' ? yBot + 16 : yTop - 8} font-size=\"11\" text-anchor=\"middle\" style=\"fill:var(--md-sys-color-primary)\"\n @pointerdown=${(ev: PointerEvent) => !open && this.type(ev, { kind: 'end', end }, 'side', (w[end] as { closed: number }).closed)}>${label}</text>\n <title>${label}</title>\n </g>`\n }\n return svg`<svg viewBox=${`0 0 ${W} ${H + 8}`} role=\"img\" aria-label=${i18next.t('figure.label.section-cavity-side')}\n @pointermove=${(ev: PointerEvent) => this.dragEnd(ev, k, yTop, yBot)}\n @pointerup=${(ev: PointerEvent) => this.releaseEnd(ev)} @pointercancel=${() => this.release()}>\n <rect x=${x0} y=${yTop} width=${wl} height=${yBot - yTop} style=${fill} />\n <rect x=${x1 - wr} y=${yTop} width=${wr} height=${yBot - yTop} style=${fill} />\n ${floor ? svg`<rect x=${x0 + wl} y=${yBot - floor} width=${x1 - x0 - wl - wr} height=${floor} style=${fill} />` : nothing}\n ${lid ? svg`<rect x=${x0 + wl} y=${yTop} width=${x1 - x0 - wl - wr} height=${lid} style=${fill} />` : nothing}\n ${this.locked ? nothing : [endZone('start', yBot, floor), endZone('end', yTop, lid)]}\n </svg>`\n }\n\n private grab(ev: PointerEvent, what: NonNullable<FigureCavityDrawing['dragging']>) {\n if (this.locked) return\n ev.stopPropagation()\n ;(ev.currentTarget as Element).closest('svg')!.setPointerCapture(ev.pointerId)\n this.dragging = what\n this.pressedAt = ev.clientY\n this.refusal = ''\n }\n\n private drag(ev: PointerEvent, e: NonNullable<FigureEvaluatedShape['extrusion']>, k: number, ox: number, oy: number, half: Record<Axis, number>) {\n const d = this.dragging\n if (d?.kind !== 'wall') return\n const [h] = SCREEN[e.axis]\n const p = this.point(ev, ev.currentTarget as SVGSVGElement)\n const a = d.side[0] as Axis,\n low = d.side[1] === '-'\n const at = a === h ? p.x - ox : p.y - oy\n const value = (half[a] - (low ? -at : at)) / k\n this.hold({ ...this.now!, wall: wallDragged(this.now!.wall, d.side, value, this.perSide) }, d.side)\n }\n\n private dragEnd(ev: PointerEvent, k: number, yTop: number, yBot: number) {\n const d = this.dragging\n if (d?.kind !== 'end' || this.now![d.end] === 'open') return\n if (Math.abs(ev.clientY - this.pressedAt) < 3 && !this.working) return\n const p = this.point(ev, ev.currentTarget as SVGSVGElement)\n const t = d.end === 'start' ? (yBot - p.y) / k : (p.y - yTop) / k\n this.hold({ ...this.now!, [d.end]: { closed: Math.max(1, Math.round(t)) } })\n }\n\n /** A press on an end that did not move is a toggle; a drag was a thickness. */\n private releaseEnd(ev: PointerEvent) {\n const d = this.dragging\n if (d?.kind === 'end' && !this.working && Math.abs(ev.clientY - this.pressedAt) < 3) {\n this.dragging = null\n const next = { ...this.now!, [d.end]: endToggled(this.body!.shape, this.now![d.end]) }\n this.refusal = this.judge(next)\n if (!this.refusal) this.emit('command', this.action(next))\n return\n }\n this.release()\n }\n}\n\n"]}
|
|
1
|
+
{"version":3,"file":"figure-cavity-drawing.js","sourceRoot":"","sources":["../../client/modeller/figure-cavity-drawing.ts"],"names":[],"mappings":"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","sourcesContent":["import { css, html, LitElement, nothing, svg } from 'lit'\nimport { customElement, property, state } from 'lit/decorators.js'\n\nimport { i18next, localize } from '@operato/i18n'\nimport { figureCavitySectionOf } from '@hatiolab/figure-model'\nimport type { FigureAuthoringAction, FigureCavityRequest, FigureEvaluatedShape, FigureSection } from '@hatiolab/figure-model'\nimport { focusOnRender } from './focus-on-render.js'\nimport { cavityRefusalWordsOf, cavityWorkingOf, END_FACE, endToggled, mm, SIDE_FACE, wallDragged } from './section-controls.js'\n\ntype Axis = 'x' | 'y' | 'z'\n\ntype End = 'start' | 'end'\ntype Body = { id: string; shape: FigureEvaluatedShape }\n\n/** How the section is laid on the screen, by the axis it is pushed along: across to the right, then down. */\nconst SCREEN: Record<Axis, [Axis, Axis]> = { y: ['x', 'z'], x: ['z', 'y'], z: ['x', 'y'] }\n\n/**\n * 속 공간 그림 — the inside of a pushed part drawn, and edited by drawing (user 2026-10-01: 「이해와 편집이 직관적이지 않다」).\n *\n * Seen along the push, the section and its inside: a handle in the middle of each wall is dragged to its thickness,\n * every wall together unless 면마다 벽 is on. Cut along the push, the walls and the two ends: an end pressed opens or\n * closes it, a closed end's inner line is dragged to its thickness. While dragging, the figure behind shows what the\n * inside makes (`command-live`); letting go sends one `set-cavity`. What the kernel would refuse is drawn in the error\n * colour and said, by the kernel's own check, and is not sent.\n */\n@customElement('figure-cavity-drawing')\nexport class FigureCavityDrawing extends localize(i18next)(LitElement) {\n static styles = css`\n :host {\n display: grid;\n gap: 6px;\n }\n svg {\n width: 100%;\n display: block;\n touch-action: none;\n user-select: none;\n }\n svg text {\n font: inherit;\n }\n small[refusal] {\n color: var(--md-sys-color-error);\n }\n div[pane] {\n position: relative;\n }\n div[pane] input {\n position: absolute;\n width: 64px;\n transform: translate(-50%, -50%);\n font: inherit;\n }\n text[typed] {\n cursor: text;\n text-decoration: underline dotted;\n }\n `\n\n @property({ attribute: false }) body?: Body\n @property({ type: Boolean }) locked = false\n /** Walls one per side: a handle moves its own wall only. */\n @property({ type: Boolean }) perSide = false\n\n /** What is being dragged, and the inside it makes; undefined when nothing is. */\n @state() private working?: ReturnType<typeof cavityWorkingOf>\n @state() private refusal = ''\n private dragging: { kind: 'wall'; side: string } | { kind: 'end'; end: End } | null = null\n /** A number pressed to be typed: which, and where on its picture (percent of the picture's box). */\n @state() private typing?: ({ kind: 'wall'; side: string } | { kind: 'end'; end: End }) & { x: number; y: number; pane: 'top' | 'side'; value: number }\n private pressedAt = 0\n\n private get now() {\n return this.working ?? (this.body ? cavityWorkingOf(this.body.shape) : undefined)\n }\n\n private request(w: NonNullable<ReturnType<typeof cavityWorkingOf>>): FigureCavityRequest {\n return { wall: { ...w.wall }, start: w.start, end: w.end }\n }\n\n private action(w: NonNullable<ReturnType<typeof cavityWorkingOf>>): FigureAuthoringAction {\n return { kind: 'set-cavity', part: this.body!.id, cavity: this.request(w) }\n }\n\n /** What the kernel would refuse, in words; for one side's wall, the most that side can be with the opposite kept. */\n private judge(w: NonNullable<ReturnType<typeof cavityWorkingOf>>, side?: string): string {\n const words = cavityRefusalWordsOf(this.body!.shape, w, this.perSide, side)\n return words ? i18next.t(words.key, words.params) : ''\n }\n\n /** The working inside while dragging: drawn, judged, and previewed behind when the kernel would take it. */\n private hold(w: NonNullable<ReturnType<typeof cavityWorkingOf>>, side?: string) {\n this.working = w\n this.refusal = this.judge(w, side)\n this.emit('command-live', this.refusal ? null : this.action(w))\n }\n\n private release() {\n const w = this.working\n this.dragging = null\n this.working = undefined\n if (!w) return\n /* Refused: nothing is sent, and the reason stays said until the next drag -- letting go must not look like taking it. */\n if (this.refusal) {\n this.emit('command-live', null)\n return\n }\n this.emit('command', this.action(w))\n }\n\n private emit(name: 'command' | 'command-live', action: FigureAuthoringAction | null) {\n this.dispatchEvent(new CustomEvent(name, { detail: { action }, bubbles: true, composed: true }))\n }\n\n private point(ev: PointerEvent, el: SVGSVGElement) {\n const pt = el.createSVGPoint()\n pt.x = ev.clientX\n pt.y = ev.clientY\n return pt.matrixTransform(el.getScreenCTM()!.inverse())\n }\n\n render() {\n const e = this.body?.shape.extrusion\n const w = this.now\n if (!e || !w || (e.section.kind !== 'rectangle' && e.section.kind !== 'ellipse')) return nothing\n return html`<div pane>${this.top(e, w)}${this.typing?.pane === 'top' ? this.renderTyping() : nothing}</div>\n <div pane>${this.side(e, w)}${this.typing?.pane === 'side' ? this.renderTyping() : nothing}</div>\n ${this.refusal ? html`<small refusal role=\"alert\">${this.refusal}</small>` : nothing}`\n }\n\n /** Press a number, type it, Enter: the same one set-cavity a drag sends; Esc or leaving puts it back. */\n private type(ev: PointerEvent, what: { kind: 'wall'; side: string } | { kind: 'end'; end: End }, pane: 'top' | 'side', value: number) {\n if (this.locked) return\n ev.stopPropagation()\n const svgEl = (ev.target as Element).closest('svg')!\n const box = svgEl.getBoundingClientRect()\n this.refusal = ''\n this.typing = { ...what, pane, value, x: ((ev.clientX - box.left) / box.width) * 100, y: ((ev.clientY - box.top) / box.height) * 100 }\n }\n\n private renderTyping() {\n const t = this.typing!\n return html`<input type=\"number\" step=\"1\" min=\"1\" .value=${String(t.value)} style=${`left:${t.x}%;top:${t.y}%`}\n aria-label=${t.kind === 'wall' ? i18next.t('figure.label.section-wall') : i18next.t('figure.label.face-' + END_FACE(this.body!.shape.extrusion!.axis, t.end))}\n @keydown=${(ev: KeyboardEvent) => {\n ev.stopPropagation()\n if (ev.key === 'Escape') this.typing = undefined\n if (ev.key !== 'Enter') return\n const value = Number((ev.target as HTMLInputElement).value)\n this.typing = undefined\n if (!(Number.isFinite(value) && value > 0)) return\n const now = this.now!\n const next = t.kind === 'wall' ? { ...now, wall: wallDragged(now.wall, t.side, value, this.perSide) } : { ...now, [t.end]: { closed: Math.round(value) } }\n this.refusal = this.judge(next, t.kind === 'wall' ? t.side : undefined)\n if (!this.refusal) this.emit('command', this.action(next))\n }}\n @blur=${() => (this.typing = undefined)}\n ${focusOnRender()} />`\n }\n\n /** Seen along the push: the section, its inside and a handle on each wall. */\n private top(e: NonNullable<FigureEvaluatedShape['extrusion']>, w: NonNullable<ReturnType<typeof cavityWorkingOf>>) {\n const [h, v] = SCREEN[e.axis]\n const s = e.section\n const across = (a: Axis) => (s.kind === 'rectangle' ? s.size[a]! : 2 * (s as { radius: Record<string, number> }).radius[a]!)\n const W = 300,\n H = 170,\n pad = 26\n /* Wider room left and right: a wall's number stands outside the section there. */\n const k = Math.min((W - 2 * (pad + 10)) / across(h), (H - 2 * pad) / across(v))\n const ox = W / 2,\n oy = H / 2\n const inside = figureCavitySectionOf(s as FigureSection, e.axis, w.wall)\n const bad = !!this.refusal || !('section' in inside)\n const shape = (sec: FigureSection, c: Partial<Record<Axis, number>>, attrs: string) => {\n const cx = ox + (c[h] ?? 0) * k,\n cy = oy + (c[v] ?? 0) * k\n if (sec.kind === 'ellipse') return svg`<ellipse cx=${cx} cy=${cy} rx=${sec.radius[h]! * k} ry=${sec.radius[v]! * k} style=${attrs} />`\n const r = sec as { size: Record<string, number>; corner?: Record<string, number> }\n return svg`<rect x=${cx - (r.size[h]! * k) / 2} y=${cy - (r.size[v]! * k) / 2} width=${r.size[h]! * k} height=${r.size[v]! * k}\n rx=${(r.corner?.[h] ?? 0) * k} ry=${(r.corner?.[v] ?? 0) * k} style=${attrs} />`\n }\n const half = { [h]: (across(h) * k) / 2, [v]: (across(v) * k) / 2 } as Record<Axis, number>\n /* Each wall's handle sits on the inside's edge, half way along it; the value is the wall's own. */\n const handles = [`${h}-`, `${h}+`, `${v}-`, `${v}+`].map(side => {\n const a = side[0] as Axis,\n low = side[1] === '-'\n const sign = low ? -1 : 1\n const edge = sign * (half[a] - w.wall[side]! * k)\n /* The two handles across a narrow inside would stand on each other: then each steps aside, the low one first. */\n const room = 2 * half[a] - (w.wall[`${a}-`]! + w.wall[`${a}+`]!) * k\n const aside = room < 16 ? sign * 9 : 0\n const x = a === h ? ox + edge : ox + aside,\n y = a === v ? oy + edge : oy + aside\n /*\n The number stands just past the section's outer edge on its own side, so the opposite wall's never meets it\n however thin the walls or shallow the section (2026-10-02: at 70 mm deep the two walls' numbers lay on each other).\n */\n const tx = a === h ? ox + sign * (half[a] + 5) : ox,\n ty = a === v ? oy + sign * (half[a] + (low ? 5 : 13)) : oy + 4\n return svg`<g wall=${side} style=${`cursor:${a === h ? 'ew-resize' : 'ns-resize'}`}\n @pointerdown=${(ev: PointerEvent) => this.grab(ev, { kind: 'wall', side })}>\n <rect x=${x - 6} y=${y - 6} width=\"12\" height=\"12\" rx=\"2\" style=\"fill:var(--md-sys-color-surface);stroke:var(--md-sys-color-primary);stroke-width:1.5\" />\n <text typed x=${tx} y=${ty} font-size=\"11\" text-anchor=${a === h ? (low ? 'end' : 'start') : 'middle'} style=\"fill:var(--md-sys-color-on-surface)\"\n @pointerdown=${(ev: PointerEvent) => this.type(ev, { kind: 'wall', side }, 'top', w.wall[side]!)}>${mm(w.wall[side]!)}</text>\n <title>${i18next.t('figure.label.face-' + SIDE_FACE[side])} ${i18next.t('figure.label.section-wall')}</title>\n </g>`\n })\n return svg`<svg viewBox=${`0 0 ${W} ${H}`} role=\"img\" aria-label=${i18next.t('figure.label.section-cavity-top')}\n @pointermove=${(ev: PointerEvent) => this.drag(ev, e, k, ox, oy, half)}\n @pointerup=${() => this.release()} @pointercancel=${() => this.release()}>\n ${shape(s as FigureSection, {}, 'fill:var(--md-sys-color-primary-container);stroke:var(--md-sys-color-primary);stroke-width:1.5')}\n ${'section' in inside\n ? shape(inside.section, inside.centre, `fill:var(--md-sys-color-surface);stroke:${bad ? 'var(--md-sys-color-error)' : 'var(--md-sys-color-primary)'};stroke-width:1.2;stroke-dasharray:4 3`)\n : nothing}\n ${this.locked ? nothing : handles}\n </svg>`\n }\n\n /** Cut along the push: the walls across the first plane axis, and the two ends -- pressed to open or close. */\n private side(e: NonNullable<FigureEvaluatedShape['extrusion']>, w: NonNullable<ReturnType<typeof cavityWorkingOf>>) {\n const [h] = SCREEN[e.axis]\n const s = e.section\n const width = s.kind === 'rectangle' ? s.size[h]! : 2 * (s as { radius: Record<string, number> }).radius[h]!\n const length = e.end - e.start\n const W = 300,\n H = 170,\n padX = 40,\n padY = 26\n const k = Math.min((W - 2 * padX) / width, (H - 2 * padY) / length)\n const x0 = W / 2 - (width * k) / 2,\n x1 = W / 2 + (width * k) / 2,\n yTop = H / 2 - (length * k) / 2,\n yBot = H / 2 + (length * k) / 2\n const wl = w.wall[`${h}-`]! * k,\n wr = w.wall[`${h}+`]! * k\n const thick = (end: End) => (w[end] === 'open' ? 0 : (w[end] as { closed: number }).closed * k)\n /* The push's start is drawn at the bottom: a tote stands on its floor. */\n const floor = thick('start'),\n lid = thick('end')\n const fill = 'fill:var(--md-sys-color-primary-container);stroke:var(--md-sys-color-primary);stroke-width:1.2'\n const endZone = (end: End, y: number, t: number) => {\n const open = w[end] === 'open'\n const words = open\n ? i18next.t('figure.label.section-end-open')\n : `${i18next.t('figure.label.section-end-closed')} ${mm((w[end] as { closed: number }).closed)}`\n const label = `${i18next.t('figure.label.face-' + END_FACE(e.axis, end))}: ${words}`\n const inner = end === 'start' ? y - t : y + t\n return svg`<g end=${end} style=${`cursor:${open ? 'pointer' : 'ns-resize'}`}\n @pointerdown=${(ev: PointerEvent) => this.grab(ev, { kind: 'end', end })}>\n <rect x=${x0 + wl} y=${Math.min(y, inner) - 8} width=${x1 - x0 - wl - wr} height=${Math.abs(t) + 16} style=\"fill:transparent\" />\n ${open ? svg`<line x1=${x0 + wl} y1=${y} x2=${x1 - wr} y2=${y} style=\"stroke:var(--md-sys-color-outline);stroke-dasharray:3 3\" />` : nothing}\n <text ?typed=${!open} x=${W / 2} y=${end === 'start' ? yBot + 16 : yTop - 8} font-size=\"11\" text-anchor=\"middle\" style=\"fill:var(--md-sys-color-primary)\"\n @pointerdown=${(ev: PointerEvent) => !open && this.type(ev, { kind: 'end', end }, 'side', (w[end] as { closed: number }).closed)}>${label}</text>\n <title>${label}</title>\n </g>`\n }\n return svg`<svg viewBox=${`0 0 ${W} ${H + 8}`} role=\"img\" aria-label=${i18next.t('figure.label.section-cavity-side')}\n @pointermove=${(ev: PointerEvent) => this.dragEnd(ev, k, yTop, yBot)}\n @pointerup=${(ev: PointerEvent) => this.releaseEnd(ev)} @pointercancel=${() => this.release()}>\n <rect x=${x0} y=${yTop} width=${wl} height=${yBot - yTop} style=${fill} />\n <rect x=${x1 - wr} y=${yTop} width=${wr} height=${yBot - yTop} style=${fill} />\n ${floor ? svg`<rect x=${x0 + wl} y=${yBot - floor} width=${x1 - x0 - wl - wr} height=${floor} style=${fill} />` : nothing}\n ${lid ? svg`<rect x=${x0 + wl} y=${yTop} width=${x1 - x0 - wl - wr} height=${lid} style=${fill} />` : nothing}\n ${this.locked ? nothing : [endZone('start', yBot, floor), endZone('end', yTop, lid)]}\n </svg>`\n }\n\n private grab(ev: PointerEvent, what: NonNullable<FigureCavityDrawing['dragging']>) {\n if (this.locked) return\n ev.stopPropagation()\n ;(ev.currentTarget as Element).closest('svg')!.setPointerCapture(ev.pointerId)\n this.dragging = what\n this.pressedAt = ev.clientY\n this.refusal = ''\n }\n\n private drag(ev: PointerEvent, e: NonNullable<FigureEvaluatedShape['extrusion']>, k: number, ox: number, oy: number, half: Record<Axis, number>) {\n const d = this.dragging\n if (d?.kind !== 'wall') return\n const [h] = SCREEN[e.axis]\n const p = this.point(ev, ev.currentTarget as SVGSVGElement)\n const a = d.side[0] as Axis,\n low = d.side[1] === '-'\n const at = a === h ? p.x - ox : p.y - oy\n const value = (half[a] - (low ? -at : at)) / k\n this.hold({ ...this.now!, wall: wallDragged(this.now!.wall, d.side, value, this.perSide) }, d.side)\n }\n\n private dragEnd(ev: PointerEvent, k: number, yTop: number, yBot: number) {\n const d = this.dragging\n if (d?.kind !== 'end' || this.now![d.end] === 'open') return\n if (Math.abs(ev.clientY - this.pressedAt) < 3 && !this.working) return\n const p = this.point(ev, ev.currentTarget as SVGSVGElement)\n const t = d.end === 'start' ? (yBot - p.y) / k : (p.y - yTop) / k\n this.hold({ ...this.now!, [d.end]: { closed: Math.max(1, Math.round(t)) } })\n }\n\n /** A press on an end that did not move is a toggle; a drag was a thickness. */\n private releaseEnd(ev: PointerEvent) {\n const d = this.dragging\n if (d?.kind === 'end' && !this.working && Math.abs(ev.clientY - this.pressedAt) < 3) {\n this.dragging = null\n const next = { ...this.now!, [d.end]: endToggled(this.body!.shape, this.now![d.end]) }\n this.refusal = this.judge(next)\n if (!this.refusal) this.emit('command', this.action(next))\n return\n }\n this.release()\n }\n}\n\n"]}
|