@things-factory/figure-ui 10.1.203 → 10.1.205
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/modeller/canvas.ts +91 -9
- package/client/modeller/editor-styles.ts +7 -22
- package/client/modeller/editor.ts +176 -145
- package/client/modeller/fasten-form.ts +91 -9
- package/client/modeller/figure-fasten-dialog.ts +42 -9
- package/client/modeller/figure-fasten-drawing.ts +233 -12
- package/client/modeller/figure-section-editor.ts +6 -6
- package/client/modeller/figure-slot-layout-panel.ts +1 -1
- package/client/modeller/gizmo.ts +12 -1
- package/client/modeller/links.ts +48 -6
- package/client/modeller/section-drawing.ts +7 -7
- package/client/modeller/size-drag.ts +112 -0
- package/client/modeller/slot-layout-host.ts +3 -3
- package/client/modeller/stage-model.ts +6 -9
- package/client/pages/figure-modeller-page.ts +1 -4
- package/dist-client/modeller/canvas.d.ts +24 -3
- package/dist-client/modeller/canvas.js +96 -11
- package/dist-client/modeller/canvas.js.map +1 -1
- package/dist-client/modeller/editor-styles.js +7 -22
- package/dist-client/modeller/editor-styles.js.map +1 -1
- package/dist-client/modeller/editor.d.ts +28 -32
- package/dist-client/modeller/editor.js +176 -153
- package/dist-client/modeller/editor.js.map +1 -1
- package/dist-client/modeller/fasten-form.d.ts +36 -3
- package/dist-client/modeller/fasten-form.js +86 -8
- package/dist-client/modeller/fasten-form.js.map +1 -1
- package/dist-client/modeller/figure-fasten-dialog.d.ts +17 -3
- package/dist-client/modeller/figure-fasten-dialog.js +47 -10
- package/dist-client/modeller/figure-fasten-dialog.js.map +1 -1
- package/dist-client/modeller/figure-fasten-drawing.d.ts +33 -1
- package/dist-client/modeller/figure-fasten-drawing.js +235 -11
- package/dist-client/modeller/figure-fasten-drawing.js.map +1 -1
- package/dist-client/modeller/figure-section-editor.d.ts +3 -3
- package/dist-client/modeller/figure-section-editor.js +4 -4
- package/dist-client/modeller/figure-section-editor.js.map +1 -1
- package/dist-client/modeller/figure-slot-layout-panel.js +1 -1
- package/dist-client/modeller/figure-slot-layout-panel.js.map +1 -1
- package/dist-client/modeller/gizmo.d.ts +12 -1
- package/dist-client/modeller/gizmo.js +8 -0
- package/dist-client/modeller/gizmo.js.map +1 -1
- package/dist-client/modeller/links.d.ts +14 -2
- package/dist-client/modeller/links.js +42 -4
- package/dist-client/modeller/links.js.map +1 -1
- package/dist-client/modeller/section-drawing.d.ts +3 -4
- package/dist-client/modeller/section-drawing.js +10 -9
- package/dist-client/modeller/section-drawing.js.map +1 -1
- package/dist-client/modeller/size-drag.d.ts +38 -0
- package/dist-client/modeller/size-drag.js +85 -0
- package/dist-client/modeller/size-drag.js.map +1 -0
- package/dist-client/modeller/slot-layout-host.d.ts +1 -3
- package/dist-client/modeller/slot-layout-host.js +3 -3
- package/dist-client/modeller/slot-layout-host.js.map +1 -1
- package/dist-client/modeller/stage-model.d.ts +5 -7
- package/dist-client/modeller/stage-model.js +6 -6
- package/dist-client/modeller/stage-model.js.map +1 -1
- package/dist-client/pages/figure-modeller-page.d.ts +0 -2
- package/dist-client/pages/figure-modeller-page.js +1 -6
- package/dist-client/pages/figure-modeller-page.js.map +1 -1
- package/dist-client/tsconfig.tsbuildinfo +1 -1
- package/dist-server/tsconfig.tsbuildinfo +1 -1
- package/package.json +7 -7
- package/test/align.test.ts +7 -11
- package/test/browser/acceptance-page.js +10 -0
- package/test/browser/editing.check.mjs +17 -13
- package/test/browser/links-page.js +2 -2
- package/test/browser/links.check.mjs +94 -56
- package/test/browser/modeller-page.js +30 -18
- package/test/browser/modeller-revision.check.mjs +39 -0
- package/test/browser/modeller.check.mjs +32 -10
- package/test/browser/screen-page.js +0 -2
- package/test/browser/screen.check.mjs +11 -13
- package/test/browser/section.check.mjs +2 -2
- package/test/fasten-form.test.ts +82 -2
- package/test/gizmo.test.ts +13 -15
- package/test/links.test.ts +8 -3
- package/test/resize-with-placement.test.ts +14 -13
- package/test/revision.test.ts +3 -2
- package/test/section-editor.test.ts +9 -10
- package/test/size-drag.test.ts +114 -0
- package/test/slot-layout-host.test.ts +13 -8
- package/translations/en.json +25 -22
- package/translations/es.json +25 -22
- package/translations/ja.json +25 -22
- package/translations/ko.json +25 -22
- package/translations/ms.json +25 -22
- package/translations/zh.json +25 -22
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"section-drawing.js","sourceRoot":"","sources":["../../client/modeller/section-drawing.ts"],"names":[],"mappings":"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","sourcesContent":["import { FIGURE_SECTION_PLANE, FIGURE_SECTION_POINT_LIMIT, checkFigureSection, figureExtrusionFeaturesOf, figureSectionSidesOf } from '@hatiolab/figure-model'\nimport type { FigureAuthoringAction, FigureCavityRequest, FigureEvaluatedShape, FigureSection, FigureSectionIssue, FigureSectionMeasure, FigureSectionPoint } from '@hatiolab/figure-model'\nimport { END_FACE } from './section-controls.js'\n\n/*\n * What the section editor does to a drawn section's points, and how it says what is wrong with them (ADR-0100 §3.2).\n * The points are the kernel's own (`{ id, x, z }` for a push along Y), their validity is the kernel's own check, and a\n * point's number on screen is its own name's number (Q9): p3 is 「3」 before and after any edit, and deleting it leaves\n * 1, 2 and 4.\n */\n\ntype Axis = 'x' | 'y' | 'z'\nexport type Points = readonly FigureSectionPoint[]\n\n/** The number a point is shown by: its name's number. */\nexport const pointLabel = (id: string) => /^p(\\d+)$/.exec(id)?.[1] ?? id\n\n/** The next point's name: one past the highest number the loop has, so a new point never takes a gap's number. */\nexport function nextPointId(points: Points): string {\n return `p${Math.max(0, ...points.map(p => Number(/^p(\\d+)$/.exec(p.id)?.[1] ?? 0))) + 1}`\n}\n\n/** A point in the middle of the side from `from` to the point after it, whole millimetres; the new point's id with it. */\nexport function insertAfter(points: Points, from: string, axis: Axis): { points: FigureSectionPoint[]; id: string } {\n const [u, v] = FIGURE_SECTION_PLANE[axis]\n const i = points.findIndex(p => p.id === from)\n const a = points[i]!,\n b = points[(i + 1) % points.length]!\n const id = nextPointId(points)\n const mid = { id, [u]: Math.round((a[u]! + b[u]!) / 2), [v]: Math.round((a[v]! + b[v]!) / 2) } as FigureSectionPoint\n return { points: [...points.slice(0, i + 1), mid, ...points.slice(i + 1)], id }\n}\n\n/** The points less one, or why not: a section is three points or more. */\nexport function removePoint(points: Points, id: string): FigureSectionPoint[] | { refused: 'too-few' } {\n if (points.length <= 3) return { refused: 'too-few' }\n return points.filter(p => p.id !== id)\n}\n\nexport function movePoint(points: Points, id: string, at: Partial<Record<Axis, number>>): FigureSectionPoint[] {\n return points.map(p => (p.id === id ? { ...p, ...at } : p))\n}\n\n/** What is wrong with the points, by the kernel's own check. */\nexport const issuesOf = (points: Points, axis: Axis) => checkFigureSection({ kind: 'polygon', points: [...points] }, axis)\n\n/** A side said in the loop's order, 3–4 not 4–3: its id is the pair in name order, which a person never sees. */\nfunction sideLabel(points: Points, axis: Axis, side: string): string {\n const s = figureSectionSidesOf({ kind: 'polygon', points: [...points] }, axis).find(x => x.id === side)\n const [a, b] = s?.from ? [s.from, s.to!] : side.split('~')\n return `${pointLabel(a!)}–${pointLabel(b!)}`\n}\n\n/** An issue as the words that say it: an i18n key and its values. */\nexport function issueWords(issue: FigureSectionIssue, points: Points, axis: Axis): { key: string; params: Record<string, string> } {\n const line = (s: string) => sideLabel(points, axis, s)\n switch (issue.code) {\n case 'SIDES_CROSS':\n return { key: 'figure.text.section-issue-cross', params: { a: line(issue.sides[0]), b: line(issue.sides[1]) } }\n case 'SIDES_TOUCH':\n return { key: 'figure.text.section-issue-touch', params: { a: line(issue.sides[0]), b: line(issue.sides[1]) } }\n case 'SIDES_FOLD':\n return { key: 'figure.text.section-issue-fold', params: { a: line(issue.sides[0]), b: line(issue.sides[1]) } }\n case 'ZERO_LENGTH_SIDE':\n return { key: 'figure.text.section-issue-zero-length', params: { a: line(issue.side) } }\n case 'ZERO_AREA':\n return { key: 'figure.text.section-issue-zero-area', params: {} }\n case 'TOO_FEW_POINTS':\n return { key: 'figure.text.section-issue-too-few', params: {} }\n case 'TOO_MANY_POINTS':\n return { key: 'figure.text.section-issue-too-many', params: { limit: String(issue.limit) } }\n case 'CORNER_TOO_LARGE':\n return { key: 'figure.text.section-issue-corner', params: { max: String(Math.round(issue.max * 1000) / 1000) } }\n default:\n return { key: 'figure.text.section-issue-number', params: {} }\n }\n}\n\n/** Every side and point an issue names, to mark on the drawing -- by more than colour: the list says them too. */\nexport function markedBy(issues: readonly FigureSectionIssue[]): { sides: Set<string>; points: Set<string> } {\n const sides = new Set<string>(),\n points = new Set<string>()\n for (const i of issues) {\n if ('sides' in i) for (const s of i.sides) sides.add(s)\n if ('side' in i) sides.add(i.side)\n if ('point' in i) points.add(i.point)\n if ('at' in i) points.add(String(i.at).split('.')[0]!)\n }\n for (const s of sides) for (const p of s.split('~')) points.add(p)\n return { sides, points }\n}\n\n/** How far the drawing reaches from the origin: the points' farthest coordinate with room around, in 50 mm steps. */\nexport function extentOf(points: Points, axis: Axis): number {\n const [u, v] = FIGURE_SECTION_PLANE[axis]\n const far = Math.max(1, ...points.flatMap(p => [Math.abs(p[u] ?? 0), Math.abs(p[v] ?? 0)]))\n return Math.ceil((far * 1.4 + 40) / 50) * 50\n}\n\nexport const POINT_LIMIT = FIGURE_SECTION_POINT_LIMIT\n\n/** What the section editor holds while it is open: the points of a drawn section, the widths across, the length. */\nexport interface SectionWorking {\n points: FigureSectionPoint[]\n /** Along each plane axis: a rectangle's size, an ellipse's diameter. Empty for a drawn section. */\n across: Partial<Record<Axis, number>>\n length: number\n /** A drawn section's end drawn to one point (a pyramid), across the plane axes; null for a push. */\n apex: Partial<Record<Axis, number>> | null\n /** A pushed rectangle's or ellipse's inside, every side's wall written out; null for none or a drawn section. */\n cavity: { wall: Record<string, number>; start: FigureCavityRequest['start']; end: FigureCavityRequest['end'] } | null\n}\n\n/** A pushed part's section, axis and ends -- or a pyramid's, whose end is its apex (figure-model `loft@1`). */\nexport function drawnOf(shape: FigureEvaluatedShape):\n | { axis: Axis; section: FigureSection; start: number; end: number; apex: Partial<Record<Axis, number>> | null }\n | undefined {\n if (shape.extrusion) return { ...shape.extrusion, apex: null }\n if (shape.loft) return { ...shape.loft, apex: shape.loft.apex }\n return undefined\n}\n\n/** Where a new apex goes: over the middle of the points' span, whole millimetres. */\nexport function apexOver(points: Points, axis: Axis): Partial<Record<Axis, number>> {\n const [u, v] = FIGURE_SECTION_PLANE[axis]\n const mid = (x: Axis) => Math.round((Math.min(...points.map(p => p[x]!)) + Math.max(...points.map(p => p[x]!))) / 2)\n return { [u]: mid(u), [v]: mid(v) }\n}\n\n/** The working state of a pushed part as it stands. */\nexport function workingOf(shape: FigureEvaluatedShape): SectionWorking {\n const e = drawnOf(shape)!\n const s = e.section\n const [u, v] = FIGURE_SECTION_PLANE[e.axis]\n const across =\n s.kind === 'rectangle'\n ? { [u]: s.size[u]!, [v]: s.size[v]! }\n : s.kind === 'ellipse'\n ? { [u]: 2 * s.radius[u]!, [v]: 2 * s.radius[v]! }\n : {}\n const c = shape.extrusion && shape.cavity\n return {\n points: s.kind === 'polygon' ? s.points.map(p => ({ ...p })) : [],\n across,\n length: e.end - e.start,\n apex: e.apex ? { ...e.apex } : null,\n cavity: c ? { wall: { ...c.wall }, start: c.start, end: c.end } : null\n }\n}\n\n/**\n * The part as the working state would make it: its section, its length from the same start, its inside -- what the\n * inside's drawing reads, so its walls are judged against the widths being typed and not the ones the editor opened with.\n */\nexport function workingShapeOf(shape: FigureEvaluatedShape, w: SectionWorking): FigureEvaluatedShape {\n const e = shape.extrusion!\n const { cavity: _, ...rest } = shape\n return {\n ...rest,\n extrusion: { ...e, section: sectionOf(shape, w), end: e.start + w.length },\n ...(w.cavity ? { cavity: { id: shape.cavity?.id ?? 'inside', wall: { ...w.cavity.wall }, start: w.cavity.start, end: w.cavity.end } } : {})\n } as FigureEvaluatedShape\n}\n\n/** The section the working state makes, of the part's own kind: its corners kept, its points or widths the working ones. */\nexport function sectionOf(shape: FigureEvaluatedShape, w: SectionWorking): FigureSection {\n const e = drawnOf(shape)!\n const s = e.section\n const [u, v] = FIGURE_SECTION_PLANE[e.axis]\n if (s.kind === 'polygon') return { kind: 'polygon', points: w.points }\n if (s.kind === 'ellipse') return { kind: 'ellipse', radius: { [u]: w.across[u]! / 2, [v]: w.across[v]! / 2 } }\n return { kind: 'rectangle', size: { [u]: w.across[u]!, [v]: w.across[v]! }, ...(s.corner ? { corner: s.corner } : {}) }\n}\n\n/** What would be refused, as words, with the section's own issues for marking points and sides. By the kernel's checks. */\nexport function workingIssuesOf(\n shape: FigureEvaluatedShape,\n w: SectionWorking\n): { issues: FigureSectionIssue[]; words: Array<{ key: string; params: Record<string, string> }> } {\n const e = drawnOf(shape)!\n const section = sectionOf(shape, w)\n const issues = checkFigureSection(section, e.axis)\n const words = issues.map(i => issueWords(i, w.points, e.axis))\n if (!(Number.isFinite(w.length) && w.length > 0)) words.push({ key: 'figure.text.section-issue-length', params: {} })\n if (w.apex && !Object.values(w.apex).every(n => Number.isFinite(n))) words.push({ key: 'figure.text.section-issue-number', params: {} })\n if (!issues.length && words.length === 0 && w.cavity) {\n const made = figureExtrusionFeaturesOf({ axis: e.axis, section, start: e.start, end: e.start + w.length }, [{ id: 'inside', ...w.cavity }])\n if ('refused' in made) {\n const r = made.refused\n words.push({ key: r.code === 'CAVITY_NO_LENGTH' ? 'figure.text.section-issue-cavity-length' : 'figure.text.section-issue-cavity-walls', params: {} })\n }\n }\n return { issues, words }\n}\n\n/** The inside said so two can be compared: its walls by side, its ends. */\nexport const cavityKeyOf = (w: SectionWorking) => (w.cavity ? [Object.entries(w.cavity.wall).sort(), w.cavity.start, w.cavity.end] : null)\n\n/**\n * The one command for everything changed since the editor opened: a drawn section's points always, and of the rest only\n * what changed -- a measure left alone may follow another value and must not be written; an apex taken away is null\n * (back to a push), an inside taken away is null.\n */\nexport function sectionActionOf(part: string, kind: FigureSection['kind'] | undefined, opened: SectionWorking, w: SectionWorking): FigureAuthoringAction {\n const changed = (a: number | undefined, b: number | undefined) => Math.abs((a ?? 0) - (b ?? 0)) > 1e-9\n const across = Object.fromEntries(Object.entries(w.across).filter(([k, v]) => changed(v, opened.across[k as Axis])))\n const apexMoved = !w.apex !== !opened.apex || (!!w.apex && Object.entries(w.apex).some(([k, v]) => changed(v, opened.apex![k as Axis])))\n const cavityMoved = JSON.stringify(cavityKeyOf(w)) !== JSON.stringify(cavityKeyOf(opened))\n return {\n kind: 'set-section',\n part,\n ...(kind === 'polygon' ? { points: w.points.map(p => ({ ...p })) } : {}),\n ...(Object.keys(across).length ? { across } : {}),\n ...(changed(w.length, opened.length) ? { length: w.length } : {}),\n ...(apexMoved ? { apex: w.apex ? { ...w.apex } : null } : {}),\n ...(cavityMoved ? { cavity: w.cavity ? { wall: { ...w.cavity.wall }, start: w.cavity.start, end: w.cavity.end } : null } : {})\n }\n}\n\n/**\n * What a measure's field says under it: that it follows another value, or -- given where along the push a length\n * change keeps the part (1 its start, -1 its end, 0 its centre) -- the face it keeps; null when there is nothing to say.\n */\nexport function measureNoteOf(measure: FigureSectionMeasure | undefined, kept: -1 | 0 | 1 | undefined, axis: Axis): { key: string; face?: string } | null {\n if (measure === 'linked') return { key: 'figure.text.section-editor-linked' }\n if (kept === undefined) return null\n if (kept === 0) return { key: 'figure.text.section-editor-keeps-centre' }\n return { key: 'figure.text.section-editor-keeps', face: END_FACE(axis, kept === 1 ? 'start' : 'end') }\n}\n\n/** The words beside a drawn section's edit button: how many points it has, and the apex when its end is one point. */\nexport function sectionPointsWordsOf(drawn: ReturnType<typeof drawnOf>): { key: string; params: Record<string, string> } | null {\n if (drawn?.section.kind !== 'polygon') return null\n return { key: drawn.apex ? 'figure.text.section-points-apex' : 'figure.text.section-points', params: { points: String(drawn.section.points.length) } }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"section-drawing.js","sourceRoot":"","sources":["../../client/modeller/section-drawing.ts"],"names":[],"mappings":"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","sourcesContent":["import { FIGURE_SECTION_PLANE, FIGURE_SECTION_POINT_LIMIT, checkFigureSection, figureExtrusionFeaturesOf, figureSectionSidesOf } from '@hatiolab/figure-model'\nimport type { FigureAuthoringAction, FigureCavityRequest, FigureEvaluatedShape, FigureSection, FigureSectionIssue, FigureSectionMeasure, FigureSectionPoint } from '@hatiolab/figure-model'\n\n/*\n * What the section editor does to a drawn section's points, and how it says what is wrong with them (ADR-0100 §3.2).\n * The points are the kernel's own (`{ id, x, z }` for a push along Y), their validity is the kernel's own check, and a\n * point's number on screen is its own name's number (Q9): p3 is 「3」 before and after any edit, and deleting it leaves\n * 1, 2 and 4.\n */\n\ntype Axis = 'x' | 'y' | 'z'\nexport type Points = readonly FigureSectionPoint[]\n\n/** The number a point is shown by: its name's number. */\nexport const pointLabel = (id: string) => /^p(\\d+)$/.exec(id)?.[1] ?? id\n\n/** The next point's name: one past the highest number the loop has, so a new point never takes a gap's number. */\nexport function nextPointId(points: Points): string {\n return `p${Math.max(0, ...points.map(p => Number(/^p(\\d+)$/.exec(p.id)?.[1] ?? 0))) + 1}`\n}\n\n/** A point in the middle of the side from `from` to the point after it, whole millimetres; the new point's id with it. */\nexport function insertAfter(points: Points, from: string, axis: Axis): { points: FigureSectionPoint[]; id: string } {\n const [u, v] = FIGURE_SECTION_PLANE[axis]\n const i = points.findIndex(p => p.id === from)\n const a = points[i]!,\n b = points[(i + 1) % points.length]!\n const id = nextPointId(points)\n const mid = { id, [u]: Math.round((a[u]! + b[u]!) / 2), [v]: Math.round((a[v]! + b[v]!) / 2) } as FigureSectionPoint\n return { points: [...points.slice(0, i + 1), mid, ...points.slice(i + 1)], id }\n}\n\n/** The points less one, or why not: a section is three points or more. */\nexport function removePoint(points: Points, id: string): FigureSectionPoint[] | { refused: 'too-few' } {\n if (points.length <= 3) return { refused: 'too-few' }\n return points.filter(p => p.id !== id)\n}\n\nexport function movePoint(points: Points, id: string, at: Partial<Record<Axis, number>>): FigureSectionPoint[] {\n return points.map(p => (p.id === id ? { ...p, ...at } : p))\n}\n\n/** What is wrong with the points, by the kernel's own check. */\nexport const issuesOf = (points: Points, axis: Axis) => checkFigureSection({ kind: 'polygon', points: [...points] }, axis)\n\n/** A side said in the loop's order, 3–4 not 4–3: its id is the pair in name order, which a person never sees. */\nfunction sideLabel(points: Points, axis: Axis, side: string): string {\n const s = figureSectionSidesOf({ kind: 'polygon', points: [...points] }, axis).find(x => x.id === side)\n const [a, b] = s?.from ? [s.from, s.to!] : side.split('~')\n return `${pointLabel(a!)}–${pointLabel(b!)}`\n}\n\n/** An issue as the words that say it: an i18n key and its values. */\nexport function issueWords(issue: FigureSectionIssue, points: Points, axis: Axis): { key: string; params: Record<string, string> } {\n const line = (s: string) => sideLabel(points, axis, s)\n switch (issue.code) {\n case 'SIDES_CROSS':\n return { key: 'figure.text.section-issue-cross', params: { a: line(issue.sides[0]), b: line(issue.sides[1]) } }\n case 'SIDES_TOUCH':\n return { key: 'figure.text.section-issue-touch', params: { a: line(issue.sides[0]), b: line(issue.sides[1]) } }\n case 'SIDES_FOLD':\n return { key: 'figure.text.section-issue-fold', params: { a: line(issue.sides[0]), b: line(issue.sides[1]) } }\n case 'ZERO_LENGTH_SIDE':\n return { key: 'figure.text.section-issue-zero-length', params: { a: line(issue.side) } }\n case 'ZERO_AREA':\n return { key: 'figure.text.section-issue-zero-area', params: {} }\n case 'TOO_FEW_POINTS':\n return { key: 'figure.text.section-issue-too-few', params: {} }\n case 'TOO_MANY_POINTS':\n return { key: 'figure.text.section-issue-too-many', params: { limit: String(issue.limit) } }\n case 'CORNER_TOO_LARGE':\n return { key: 'figure.text.section-issue-corner', params: { max: String(Math.round(issue.max * 1000) / 1000) } }\n default:\n return { key: 'figure.text.section-issue-number', params: {} }\n }\n}\n\n/** Every side and point an issue names, to mark on the drawing -- by more than colour: the list says them too. */\nexport function markedBy(issues: readonly FigureSectionIssue[]): { sides: Set<string>; points: Set<string> } {\n const sides = new Set<string>(),\n points = new Set<string>()\n for (const i of issues) {\n if ('sides' in i) for (const s of i.sides) sides.add(s)\n if ('side' in i) sides.add(i.side)\n if ('point' in i) points.add(i.point)\n if ('at' in i) points.add(String(i.at).split('.')[0]!)\n }\n for (const s of sides) for (const p of s.split('~')) points.add(p)\n return { sides, points }\n}\n\n/** How far the drawing reaches from the origin: the points' farthest coordinate with room around, in 50 mm steps. */\nexport function extentOf(points: Points, axis: Axis): number {\n const [u, v] = FIGURE_SECTION_PLANE[axis]\n const far = Math.max(1, ...points.flatMap(p => [Math.abs(p[u] ?? 0), Math.abs(p[v] ?? 0)]))\n return Math.ceil((far * 1.4 + 40) / 50) * 50\n}\n\nexport const POINT_LIMIT = FIGURE_SECTION_POINT_LIMIT\n\n/** What the section editor holds while it is open: the points of a drawn section, the widths across, the length. */\nexport interface SectionWorking {\n points: FigureSectionPoint[]\n /** Along each plane axis: a rectangle's size, an ellipse's diameter. Empty for a drawn section. */\n across: Partial<Record<Axis, number>>\n length: number\n /** A drawn section's end drawn to one point (a pyramid), across the plane axes; null for a push. */\n apex: Partial<Record<Axis, number>> | null\n /** A pushed rectangle's or ellipse's inside, every side's wall written out; null for none or a drawn section. */\n cavity: { wall: Record<string, number>; start: FigureCavityRequest['start']; end: FigureCavityRequest['end'] } | null\n}\n\n/** A pushed part's section, axis and ends -- or a pyramid's, whose end is its apex (figure-model `loft@1`). */\nexport function drawnOf(shape: FigureEvaluatedShape):\n | { axis: Axis; section: FigureSection; start: number; end: number; apex: Partial<Record<Axis, number>> | null }\n | undefined {\n if (shape.extrusion) return { ...shape.extrusion, apex: null }\n if (shape.loft) return { ...shape.loft, apex: shape.loft.apex }\n return undefined\n}\n\n/** Where a new apex goes: over the middle of the points' span, whole millimetres. */\nexport function apexOver(points: Points, axis: Axis): Partial<Record<Axis, number>> {\n const [u, v] = FIGURE_SECTION_PLANE[axis]\n const mid = (x: Axis) => Math.round((Math.min(...points.map(p => p[x]!)) + Math.max(...points.map(p => p[x]!))) / 2)\n return { [u]: mid(u), [v]: mid(v) }\n}\n\n/** The working state of a pushed part as it stands. */\nexport function workingOf(shape: FigureEvaluatedShape): SectionWorking {\n const e = drawnOf(shape)!\n const s = e.section\n const [u, v] = FIGURE_SECTION_PLANE[e.axis]\n const across =\n s.kind === 'rectangle'\n ? { [u]: s.size[u]!, [v]: s.size[v]! }\n : s.kind === 'ellipse'\n ? { [u]: 2 * s.radius[u]!, [v]: 2 * s.radius[v]! }\n : {}\n const c = shape.extrusion && shape.cavity\n return {\n points: s.kind === 'polygon' ? s.points.map(p => ({ ...p })) : [],\n across,\n length: e.end - e.start,\n apex: e.apex ? { ...e.apex } : null,\n cavity: c ? { wall: { ...c.wall }, start: c.start, end: c.end } : null\n }\n}\n\n/**\n * The part as the working state would make it: its section, its length from the same start, its inside -- what the\n * inside's drawing reads, so its walls are judged against the widths being typed and not the ones the editor opened with.\n */\nexport function workingShapeOf(shape: FigureEvaluatedShape, w: SectionWorking): FigureEvaluatedShape {\n const e = shape.extrusion!\n const { cavity: _, ...rest } = shape\n return {\n ...rest,\n extrusion: { ...e, section: sectionOf(shape, w), end: e.start + w.length },\n ...(w.cavity ? { cavity: { id: shape.cavity?.id ?? 'inside', wall: { ...w.cavity.wall }, start: w.cavity.start, end: w.cavity.end } } : {})\n } as FigureEvaluatedShape\n}\n\n/** The section the working state makes, of the part's own kind: its corners kept, its points or widths the working ones. */\nexport function sectionOf(shape: FigureEvaluatedShape, w: SectionWorking): FigureSection {\n const e = drawnOf(shape)!\n const s = e.section\n const [u, v] = FIGURE_SECTION_PLANE[e.axis]\n if (s.kind === 'polygon') return { kind: 'polygon', points: w.points }\n if (s.kind === 'ellipse') return { kind: 'ellipse', radius: { [u]: w.across[u]! / 2, [v]: w.across[v]! / 2 } }\n return { kind: 'rectangle', size: { [u]: w.across[u]!, [v]: w.across[v]! }, ...(s.corner ? { corner: s.corner } : {}) }\n}\n\n/** What would be refused, as words, with the section's own issues for marking points and sides. By the kernel's checks. */\nexport function workingIssuesOf(\n shape: FigureEvaluatedShape,\n w: SectionWorking\n): { issues: FigureSectionIssue[]; words: Array<{ key: string; params: Record<string, string> }> } {\n const e = drawnOf(shape)!\n const section = sectionOf(shape, w)\n const issues = checkFigureSection(section, e.axis)\n const words = issues.map(i => issueWords(i, w.points, e.axis))\n if (!(Number.isFinite(w.length) && w.length > 0)) words.push({ key: 'figure.text.section-issue-length', params: {} })\n if (w.apex && !Object.values(w.apex).every(n => Number.isFinite(n))) words.push({ key: 'figure.text.section-issue-number', params: {} })\n if (!issues.length && words.length === 0 && w.cavity) {\n const made = figureExtrusionFeaturesOf({ axis: e.axis, section, start: e.start, end: e.start + w.length }, [{ id: 'inside', ...w.cavity }])\n if ('refused' in made) {\n const r = made.refused\n words.push({ key: r.code === 'CAVITY_NO_LENGTH' ? 'figure.text.section-issue-cavity-length' : 'figure.text.section-issue-cavity-walls', params: {} })\n }\n }\n return { issues, words }\n}\n\n/** The inside said so two can be compared: its walls by side, its ends. */\nexport const cavityKeyOf = (w: SectionWorking) => (w.cavity ? [Object.entries(w.cavity.wall).sort(), w.cavity.start, w.cavity.end] : null)\n\n/**\n * The one command for everything changed since the editor opened: a drawn section's points always, and of the rest only\n * what changed -- a measure left alone may follow another value and must not be written; an apex taken away is null\n * (back to a push), an inside taken away is null.\n */\nexport function sectionActionOf(part: string, kind: FigureSection['kind'] | undefined, opened: SectionWorking, w: SectionWorking): FigureAuthoringAction {\n const changed = (a: number | undefined, b: number | undefined) => Math.abs((a ?? 0) - (b ?? 0)) > 1e-9\n const across = Object.fromEntries(Object.entries(w.across).filter(([k, v]) => changed(v, opened.across[k as Axis])))\n const apexMoved = !w.apex !== !opened.apex || (!!w.apex && Object.entries(w.apex).some(([k, v]) => changed(v, opened.apex![k as Axis])))\n const cavityMoved = JSON.stringify(cavityKeyOf(w)) !== JSON.stringify(cavityKeyOf(opened))\n return {\n kind: 'set-section',\n part,\n ...(kind === 'polygon' ? { points: w.points.map(p => ({ ...p })) } : {}),\n ...(Object.keys(across).length ? { across } : {}),\n ...(changed(w.length, opened.length) ? { length: w.length } : {}),\n ...(apexMoved ? { apex: w.apex ? { ...w.apex } : null } : {}),\n ...(cavityMoved ? { cavity: w.cavity ? { wall: { ...w.cavity.wall }, start: w.cavity.start, end: w.cavity.end } : null } : {})\n }\n}\n\n/**\n * What a measure's field says under it: that it follows another value, or what a measure typed keeps -- the part's\n * middle, or its fastening (ADR-0140 4.1, figure-model's `figureSizeEditOf`); null when there is nothing to say.\n */\nexport function measureNoteOf(measure: FigureSectionMeasure | undefined, kept: 'centre' | 'relation' | 'none' | undefined): { key: string } | null {\n if (measure === 'linked') return { key: 'figure.text.section-editor-linked' }\n if (kept === 'centre') return { key: 'figure.text.size-keeps-centre' }\n if (kept === 'relation') return { key: 'figure.text.size-keeps-fastening' }\n if (kept === 'none') return { key: 'figure.text.size-keeps-none' }\n return null\n}\n\n/** The words beside a drawn section's edit button: how many points it has, and the apex when its end is one point. */\nexport function sectionPointsWordsOf(drawn: ReturnType<typeof drawnOf>): { key: string; params: Record<string, string> } | null {\n if (drawn?.section.kind !== 'polygon') return null\n return { key: drawn.apex ? 'figure.text.section-points-apex' : 'figure.text.section-points', params: { points: String(drawn.section.points.length) } }\n}\n"]}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import type { FigureAsset, FigureInputChange, FigureSizeKeep } from '@hatiolab/figure-model';
|
|
2
|
+
import type { FigureRenderPart } from './renderer.js';
|
|
3
|
+
export interface SizeDragFrame {
|
|
4
|
+
/** What a release now would write: the sizes and, for a free part, its own position. */
|
|
5
|
+
changes: FigureInputChange[];
|
|
6
|
+
/**
|
|
7
|
+
* Every body moved or reshaped since the drag began, by id: its pose and shape at this frame as figure-model evaluates
|
|
8
|
+
* them. The evaluator tells only what changed since the frame before; a body that moved and then stood still is kept.
|
|
9
|
+
*/
|
|
10
|
+
moved: Map<string, Pick<FigureRenderPart, 'pose' | 'shape'>>;
|
|
11
|
+
}
|
|
12
|
+
export interface SizeDrag {
|
|
13
|
+
part: string;
|
|
14
|
+
keep: FigureSizeKeep;
|
|
15
|
+
frame(sizes: readonly FigureInputChange[]): SizeDragFrame;
|
|
16
|
+
}
|
|
17
|
+
/** The drag of `part`'s size from `inputs` (the figure's inputs as it is drawn), keeping what `keep` says. */
|
|
18
|
+
export declare function startSizeDrag(asset: FigureAsset, part: string, inputs: Record<string, number>, keep: FigureSizeKeep): SizeDrag;
|
|
19
|
+
/**
|
|
20
|
+
* What a size typed for this part keeps, in figure-model's words: its middle (`centre`), its fastening (`relation`), or
|
|
21
|
+
* no point -- its position is worked out, and only the size changes (`none`). The words beside the size fields (ADR-0140
|
|
22
|
+
* 4.1, chief architect 10-20); nothing when the part cannot be asked.
|
|
23
|
+
*/
|
|
24
|
+
export declare function keptBySizeOf(asset: FigureAsset, part: string): 'centre' | 'relation' | 'none' | undefined;
|
|
25
|
+
/** The words for what a size keeps, by `keptBySizeOf`'s answer. */
|
|
26
|
+
export declare const SIZE_KEEPS_WORDS: {
|
|
27
|
+
readonly centre: "figure.text.size-keeps-centre";
|
|
28
|
+
readonly relation: "figure.text.size-keeps-fastening";
|
|
29
|
+
readonly none: "figure.text.size-keeps-none";
|
|
30
|
+
};
|
|
31
|
+
/** The parts drawn this frame: each one the frame moved, with its new pose and shape; every other one as it was. */
|
|
32
|
+
export declare function partsAtFrame(parts: readonly FigureRenderPart[], moved: SizeDragFrame['moved']): FigureRenderPart[];
|
|
33
|
+
/**
|
|
34
|
+
* How far a free part goes past its figure's mounting plane, in millimetres, as drawn: its real shape's extreme against
|
|
35
|
+
* the side the placement uses (figure-model's reach, the rule a fastening stands a part by). 0 when it does not, for a
|
|
36
|
+
* fastened part -- its fastening places it -- and for a figure placed by its centre (ADR-0140 5).
|
|
37
|
+
*/
|
|
38
|
+
export declare function throughPlaneOf(asset: FigureAsset, parts: readonly FigureRenderPart[], part: string): number;
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import { compileFigureDocument, figurePlacementOf, figureShapeReachOf, figureSizeEditOf, figureSizeEditorOf } from '@hatiolab/figure-model';
|
|
2
|
+
import { ownerOf } from './fields.js';
|
|
3
|
+
/** The drag of `part`'s size from `inputs` (the figure's inputs as it is drawn), keeping what `keep` says. */
|
|
4
|
+
export function startSizeDrag(asset, part, inputs, keep) {
|
|
5
|
+
const edit = figureSizeEditorOf(asset, part);
|
|
6
|
+
const evaluator = compileFigureDocument(asset.document).evaluator({ changes: true });
|
|
7
|
+
const base = { ...asset.designInputs, ...asset.stateDefaults, ...inputs };
|
|
8
|
+
/* The bodies as the evaluator numbers its slots: the order of this first evaluation. */
|
|
9
|
+
let ids = evaluator.evaluate(base).geometry.map(g => g.id);
|
|
10
|
+
const moved = new Map();
|
|
11
|
+
return {
|
|
12
|
+
part,
|
|
13
|
+
keep,
|
|
14
|
+
frame(sizes) {
|
|
15
|
+
const { changes } = edit(sizes, keep);
|
|
16
|
+
const next = { ...base };
|
|
17
|
+
for (const c of changes)
|
|
18
|
+
next[c.input] = c.value;
|
|
19
|
+
const step = evaluator.advance(next);
|
|
20
|
+
if (step.kind === 'changes' && step.structure)
|
|
21
|
+
ids = step.structure.ids;
|
|
22
|
+
for (let k = 0; k < step.bodies.length; k++) {
|
|
23
|
+
const id = ids[step.bodies[k]];
|
|
24
|
+
const p = step.poses.subarray(k * 12, k * 12 + 12);
|
|
25
|
+
if (id === undefined || Number.isNaN(p[0]))
|
|
26
|
+
continue;
|
|
27
|
+
const pose = { r: [[p[0], p[1], p[2]], [p[3], p[4], p[5]], [p[6], p[7], p[8]]], t: [p[9], p[10], p[11]] };
|
|
28
|
+
/* The evaluator's shapes are frozen; the scene's builder writes into what it is given, so the canvas gets its own copy. */
|
|
29
|
+
const frozen = step.kind === 'changes' ? step.shapes[k] : undefined;
|
|
30
|
+
const shape = frozen ? structuredClone(frozen) : undefined;
|
|
31
|
+
const had = moved.get(id);
|
|
32
|
+
moved.set(id, { pose, ...(shape ? { shape: shape } : had?.shape ? { shape: had.shape } : {}) });
|
|
33
|
+
}
|
|
34
|
+
return { changes, moved: new Map(moved) };
|
|
35
|
+
}
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* What a size typed for this part keeps, in figure-model's words: its middle (`centre`), its fastening (`relation`), or
|
|
40
|
+
* no point -- its position is worked out, and only the size changes (`none`). The words beside the size fields (ADR-0140
|
|
41
|
+
* 4.1, chief architect 10-20); nothing when the part cannot be asked.
|
|
42
|
+
*/
|
|
43
|
+
export function keptBySizeOf(asset, part) {
|
|
44
|
+
try {
|
|
45
|
+
const kept = figureSizeEditOf(asset, part, [], { keep: 'centre' }).kept;
|
|
46
|
+
return kept === 'opposite' ? undefined : kept;
|
|
47
|
+
}
|
|
48
|
+
catch {
|
|
49
|
+
return undefined;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
/** The words for what a size keeps, by `keptBySizeOf`'s answer. */
|
|
53
|
+
export const SIZE_KEEPS_WORDS = { centre: 'figure.text.size-keeps-centre', relation: 'figure.text.size-keeps-fastening', none: 'figure.text.size-keeps-none' };
|
|
54
|
+
/** The parts drawn this frame: each one the frame moved, with its new pose and shape; every other one as it was. */
|
|
55
|
+
export function partsAtFrame(parts, moved) {
|
|
56
|
+
if (!moved.size)
|
|
57
|
+
return parts;
|
|
58
|
+
return parts.map(part => {
|
|
59
|
+
const now = moved.get(part.id);
|
|
60
|
+
return now ? { ...part, pose: now.pose, ...(now.shape ? { shape: now.shape } : {}) } : part;
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
/** The side of its mounting plane a figure uses (ADR-0097 4.2): up from a floor, down from a ceiling, out of a wall. */
|
|
64
|
+
const USED = { floor: [0, 1, 0], ceiling: [0, -1, 0], wall: [0, 0, 1], center: undefined };
|
|
65
|
+
/**
|
|
66
|
+
* How far a free part goes past its figure's mounting plane, in millimetres, as drawn: its real shape's extreme against
|
|
67
|
+
* the side the placement uses (figure-model's reach, the rule a fastening stands a part by). 0 when it does not, for a
|
|
68
|
+
* fastened part -- its fastening places it -- and for a figure placed by its centre (ADR-0140 5).
|
|
69
|
+
*/
|
|
70
|
+
export function throughPlaneOf(asset, parts, part) {
|
|
71
|
+
const n = USED[figurePlacementOf(asset)];
|
|
72
|
+
if (!n || (asset.joints ?? []).some(j => j.body1.part === part))
|
|
73
|
+
return 0;
|
|
74
|
+
let lowest = Infinity;
|
|
75
|
+
for (const body of parts) {
|
|
76
|
+
if (ownerOf(body.id) !== part)
|
|
77
|
+
continue;
|
|
78
|
+
const { r, t } = body.pose;
|
|
79
|
+
/* The side's direction in the body's own frame: rᵀ n. */
|
|
80
|
+
const d = [0, 1, 2].map(j => r[0][j] * n[0] + r[1][j] * n[1] + r[2][j] * n[2]);
|
|
81
|
+
lowest = Math.min(lowest, t[0] * n[0] + t[1] * n[1] + t[2] * n[2] + figureShapeReachOf(body.shape, d).min);
|
|
82
|
+
}
|
|
83
|
+
return Number.isFinite(lowest) && lowest < 0 ? Math.round(-lowest * 10) / 10 : 0;
|
|
84
|
+
}
|
|
85
|
+
//# sourceMappingURL=size-drag.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"size-drag.js","sourceRoot":"","sources":["../../client/modeller/size-drag.ts"],"names":[],"mappings":"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","sourcesContent":["import { compileFigureDocument, figurePlacementOf, figureShapeReachOf, figureSizeEditOf, figureSizeEditorOf } from '@hatiolab/figure-model'\nimport type { FigureAsset, FigureInputChange, FigureSizeKeep } from '@hatiolab/figure-model'\n\nimport { ownerOf } from './fields.js'\nimport type { FigureRenderPart } from './renderer.js'\n\n/*\n * A size drag drawn from figure-model, frame by frame (ADR-0140 4.4). The gizmo says only which handle and how far; the\n * one size function (`figureSizeEditorOf`) turns the sizes into the changes a commit writes, and the instance evaluator\n * the figure is compiled into once, when the drag begins, steps to them (`advance`). What is drawn while dragging is\n * what the release writes: the same function, the same sizes, the same keep. Nothing drawn goes back into what the\n * gizmo computes (2026-09-24: the gizmo fought the modeller when evaluations were written back onto it).\n */\n\nexport interface SizeDragFrame {\n /** What a release now would write: the sizes and, for a free part, its own position. */\n changes: FigureInputChange[]\n /**\n * Every body moved or reshaped since the drag began, by id: its pose and shape at this frame as figure-model evaluates\n * them. The evaluator tells only what changed since the frame before; a body that moved and then stood still is kept.\n */\n moved: Map<string, Pick<FigureRenderPart, 'pose' | 'shape'>>\n}\n\nexport interface SizeDrag {\n part: string\n keep: FigureSizeKeep\n frame(sizes: readonly FigureInputChange[]): SizeDragFrame\n}\n\ntype Pose = FigureRenderPart['pose']\n\n/** The drag of `part`'s size from `inputs` (the figure's inputs as it is drawn), keeping what `keep` says. */\nexport function startSizeDrag(asset: FigureAsset, part: string, inputs: Record<string, number>, keep: FigureSizeKeep): SizeDrag {\n const edit = figureSizeEditorOf(asset, part)\n const evaluator = compileFigureDocument(asset.document).evaluator({ changes: true })\n const base = { ...asset.designInputs, ...asset.stateDefaults, ...inputs }\n /* The bodies as the evaluator numbers its slots: the order of this first evaluation. */\n let ids = evaluator.evaluate(base).geometry.map(g => (g as { id: string }).id)\n const moved = new Map<string, Pick<FigureRenderPart, 'pose' | 'shape'>>()\n return {\n part,\n keep,\n frame(sizes) {\n const { changes } = edit(sizes, keep)\n const next = { ...base }\n for (const c of changes) next[c.input] = c.value as number\n const step = evaluator.advance(next)\n if (step.kind === 'changes' && step.structure) ids = step.structure.ids\n for (let k = 0; k < step.bodies.length; k++) {\n const id = ids[step.bodies[k]!]\n const p = step.poses.subarray(k * 12, k * 12 + 12)\n if (id === undefined || Number.isNaN(p[0]!)) continue\n const pose: Pose = { r: [[p[0]!, p[1]!, p[2]!], [p[3]!, p[4]!, p[5]!], [p[6]!, p[7]!, p[8]!]], t: [p[9]!, p[10]!, p[11]!] }\n /* The evaluator's shapes are frozen; the scene's builder writes into what it is given, so the canvas gets its own copy. */\n const frozen = step.kind === 'changes' ? step.shapes[k] : undefined\n const shape = frozen ? structuredClone(frozen) : undefined\n const had = moved.get(id)\n moved.set(id, { pose, ...(shape ? { shape: shape as unknown as FigureRenderPart['shape'] } : had?.shape ? { shape: had.shape } : {}) } as Pick<FigureRenderPart, 'pose' | 'shape'>)\n }\n return { changes, moved: new Map(moved) }\n }\n }\n}\n\n/**\n * What a size typed for this part keeps, in figure-model's words: its middle (`centre`), its fastening (`relation`), or\n * no point -- its position is worked out, and only the size changes (`none`). The words beside the size fields (ADR-0140\n * 4.1, chief architect 10-20); nothing when the part cannot be asked.\n */\nexport function keptBySizeOf(asset: FigureAsset, part: string): 'centre' | 'relation' | 'none' | undefined {\n try {\n const kept = figureSizeEditOf(asset, part, [], { keep: 'centre' }).kept\n return kept === 'opposite' ? undefined : kept\n } catch {\n return undefined\n }\n}\n\n/** The words for what a size keeps, by `keptBySizeOf`'s answer. */\nexport const SIZE_KEEPS_WORDS = { centre: 'figure.text.size-keeps-centre', relation: 'figure.text.size-keeps-fastening', none: 'figure.text.size-keeps-none' } as const\n\n/** The parts drawn this frame: each one the frame moved, with its new pose and shape; every other one as it was. */\nexport function partsAtFrame(parts: readonly FigureRenderPart[], moved: SizeDragFrame['moved']): FigureRenderPart[] {\n if (!moved.size) return parts as FigureRenderPart[]\n return parts.map(part => {\n const now = moved.get(part.id)\n return now ? { ...part, pose: now.pose, ...(now.shape ? { shape: now.shape } : {}) } : part\n })\n}\n\n/** The side of its mounting plane a figure uses (ADR-0097 4.2): up from a floor, down from a ceiling, out of a wall. */\nconst USED: Record<string, [number, number, number] | undefined> = { floor: [0, 1, 0], ceiling: [0, -1, 0], wall: [0, 0, 1], center: undefined }\n\n/**\n * How far a free part goes past its figure's mounting plane, in millimetres, as drawn: its real shape's extreme against\n * the side the placement uses (figure-model's reach, the rule a fastening stands a part by). 0 when it does not, for a\n * fastened part -- its fastening places it -- and for a figure placed by its centre (ADR-0140 5).\n */\nexport function throughPlaneOf(asset: FigureAsset, parts: readonly FigureRenderPart[], part: string): number {\n const n = USED[figurePlacementOf(asset)]\n if (!n || (asset.joints ?? []).some(j => j.body1.part === part)) return 0\n let lowest = Infinity\n for (const body of parts) {\n if (ownerOf(body.id) !== part) continue\n const { r, t } = body.pose\n /* The side's direction in the body's own frame: rᵀ n. */\n const d = [0, 1, 2].map(j => r[0]![j]! * n[0] + r[1]![j]! * n[1] + r[2]![j]! * n[2]) as [number, number, number]\n lowest = Math.min(lowest, t[0]! * n[0] + t[1]! * n[1] + t[2]! * n[2] + figureShapeReachOf(body.shape as never, d).min)\n }\n return Number.isFinite(lowest) && lowest < 0 ? Math.round(-lowest * 10) / 10 : 0\n}\n"]}
|
|
@@ -37,12 +37,10 @@ export declare function anchorFacesOf(anchors: readonly SlotAnchor[], geometry:
|
|
|
37
37
|
* a one-anchor preset on the first, a twin fork on the first two. A single slot stands on a top and hangs from a bottom.
|
|
38
38
|
* The editor's own controls then make it what the equipment is.
|
|
39
39
|
*/
|
|
40
|
-
export declare function slotPresetsOf(anchors: readonly SlotAnchor[]
|
|
40
|
+
export declare function slotPresetsOf(anchors: readonly SlotAnchor[]): {
|
|
41
41
|
key: import("@hatiolab/figure-model").SlotLayoutPresetKey;
|
|
42
|
-
label: string;
|
|
43
42
|
params: {
|
|
44
43
|
key: string;
|
|
45
|
-
label: string;
|
|
46
44
|
integer: boolean;
|
|
47
45
|
}[];
|
|
48
46
|
build: (size: SlotPresetSize, params: Record<string, number>) => SlotLayout;
|
|
@@ -33,14 +33,14 @@ export function anchorFacesOf(anchors, geometry) {
|
|
|
33
33
|
* a one-anchor preset on the first, a twin fork on the first two. A single slot stands on a top and hangs from a bottom.
|
|
34
34
|
* The editor's own controls then make it what the equipment is.
|
|
35
35
|
*/
|
|
36
|
-
export function slotPresetsOf(anchors
|
|
36
|
+
export function slotPresetsOf(anchors) {
|
|
37
37
|
const first = anchors[0];
|
|
38
38
|
const on = { ...(first ? { anchor: first.id } : {}), ...(anchors.length >= 2 ? { forks: [anchors[0].id, anchors[1].id] } : {}) };
|
|
39
39
|
const mount = first?.face === 'bottom' ? 'HANG' : 'ON';
|
|
40
40
|
return SLOT_LAYOUT_PRESET_KEYS.map(key => ({
|
|
41
41
|
key,
|
|
42
|
-
|
|
43
|
-
params: SLOT_LAYOUT_PRESET_PARAMS[key].map(p => ({ key: p.key,
|
|
42
|
+
/* The editor names a preset and its values from their keys (@operato/slot-layout-editor's own words). */
|
|
43
|
+
params: SLOT_LAYOUT_PRESET_PARAMS[key].map(p => ({ key: p.key, integer: p.integer })),
|
|
44
44
|
build: (size, params) => slotLayoutPreset(key, size, params, { ...on, mount })
|
|
45
45
|
}));
|
|
46
46
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"slot-layout-host.js","sourceRoot":"","sources":["../../client/modeller/slot-layout-host.ts"],"names":[],"mappings":"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","sourcesContent":["/*\n * What the Figure modeller gives the shared slot layout editor (`@operato/slot-layout-editor`, the one fmsim hosts too),\n * and what it makes of the editor's result (ADR-0118). The editor edits tiers and slots; the modeller owns the anchors\n * -- a part's top or bottom face, named -- and sends the whole layout as one `set-slot-layout` command.\n *\n * A figure's released slot layout is the only one there is (ADR-0118 decision 8, user): no scene or run overrides it, so\n * this host offers no \"use default\" and no per-instance value.\n *\n * Kept free of Lit, i18n and the editor's element so node tests read it directly.\n */\nimport {\n figureShapeBoundsOf,\n figureSlotLayoutOf,\n figureSlotLayoutIssues,\n slotLayoutPreset,\n SLOT_LAYOUT_PRESET_KEYS,\n SLOT_LAYOUT_PRESET_PARAMS,\n type FigureAsset,\n type SlotLayout,\n type SlotPresetSize\n} from '@hatiolab/figure-model'\nimport type { FigureRenderPart } from './renderer.js'\n\nexport type SlotAnchorFace = 'top' | 'bottom'\nexport interface SlotAnchor {\n id: string\n part: string\n face: SlotAnchorFace\n}\n/** What the panel edits besides the tiers: the layout's name, what its slots are, and the anchors they stand on. */\nexport interface SlotLayoutForm {\n label: string\n role: 'seat' | 'grip'\n anchors: SlotAnchor[]\n}\n/** A layout problem as the editor shows it: a code, where, and its values. */\nexport interface SlotEditorIssue {\n code: string\n path: string\n params?: Record<string, string | number>\n}\n\ntype Body = { id: string; shape?: Parameters<typeof figureShapeBoundsOf>[0] }\n\n/** The figure's layout as the form and the layout, or a form to start one from on the selected part's top. */\nexport function slotLayoutFormOf(asset: FigureAsset, part: string): { form: SlotLayoutForm; layout?: SlotLayout } {\n const had = figureSlotLayoutOf(asset as never)\n if (had) return { form: { label: had.label, role: had.role, anchors: had.anchors.map(a => ({ ...a, face: a.face as SlotAnchorFace })) }, layout: had.layout }\n return { form: { label: '', role: 'seat', anchors: part ? [{ id: part, part, face: 'top' }] : [] } }\n}\n\n/** How big each anchor's face is, along the part's own X (width) and Z (depth): what the editor checks slots against. */\nexport function anchorFacesOf(anchors: readonly SlotAnchor[], geometry: readonly Body[]): Record<string, { width: number; depth: number }> {\n const out: Record<string, { width: number; depth: number }> = {}\n for (const a of anchors) {\n const body = geometry.find(g => g.id === a.part)\n if (!body?.shape) continue\n const b = figureShapeBoundsOf(body.shape)\n out[a.id] = { width: b.x.max - b.x.min, depth: b.z.max - b.z.min }\n }\n return out\n}\n\n/**\n * Where an author starts: the equipment presets (figure-model, ADR-0118 decision 8), laid out on this figure's anchors --\n * a one-anchor preset on the first, a twin fork on the first two. A single slot stands on a top and hangs from a bottom.\n * The editor's own controls then make it what the equipment is.\n */\nexport function slotPresetsOf(anchors: readonly SlotAnchor[], say: (key: string) => string) {\n const first = anchors[0]\n const on = { ...(first ? { anchor: first.id } : {}), ...(anchors.length >= 2 ? { forks: [anchors[0]!.id, anchors[1]!.id] as [string, string] } : {}) }\n const mount = first?.face === 'bottom' ? ('HANG' as const) : ('ON' as const)\n return SLOT_LAYOUT_PRESET_KEYS.map(key => ({\n key,\n label: say(`figure.label.slot-preset-${key}`),\n params: SLOT_LAYOUT_PRESET_PARAMS[key].map(p => ({ key: p.key, label: say(`figure.label.slot-preset-param-${p.key}`), integer: p.integer })),\n build: (size: SlotPresetSize, params: Record<string, number>) => slotLayoutPreset(key, size, params, { ...on, mount })\n }))\n}\n\n/*\n * What figure-model asks beyond the editor's own checks: every slot names the types it takes (ADR-0118 decision 5) -- the\n * editor's \"any type\" is a board's, not a figure's. The kernel's own check (`figureSlotLayoutIssues`, the one a\n * placement's override is held to as well), said before Apply rather than refused after it; the editor already shows the\n * common findings, so only the figure's own are added.\n */\nexport function figureSlotIssues(layout: SlotLayout, anchors: readonly string[] = layout.tiers.map(t => t.anchorId)): SlotEditorIssue[] {\n return figureSlotLayoutIssues(layout, anchors).filter(issue => issue.code === 'ACCEPTS_REQUIRED')\n}\n\n/** The command the panel sends: the whole layout, its anchors and its name, as one step of the history. */\nexport function slotLayoutCommandOf(form: SlotLayoutForm, layout: SlotLayout, fallbackLabel: string) {\n return {\n kind: 'set-slot-layout' as const,\n label: form.label.trim() || fallbackLabel,\n role: form.role,\n anchors: form.anchors.map(a => ({ id: a.id.trim(), part: a.part, face: a.face })),\n layout: structuredClone(layout)\n }\n}\n\n/** A new anchor's id: the part's, or the part's with a number when that is taken. */\nexport function anchorIdFor(part: string, taken: readonly string[]): string {\n if (!taken.includes(part)) return part\n let n = 2\n while (taken.includes(`${part}_${n}`)) n++\n return `${part}_${n}`\n}\n\n/* The token the canvas draws slots in: translucent, never picked, never saved. */\nexport const SLOT_MARK = '__slot'\n\ntype Evaluated = { id: string; pose: { r: number[][]; t: number[] }; region: { dimensions: number[] } | null }\n\n/**\n * The unfolded slots as boxes the canvas draws (ADR-0118 decision 4): each as big as what it allows, standing on its\n * place -- or hanging from it, for a tier that hangs things -- so an author sees where every slot of the rule falls.\n */\nexport function slotMarksOf(places: readonly Evaluated[], layout: SlotLayout | undefined) {\n if (!layout) return []\n const mountOf = new Map(layout.tiers.map(t => [t.tierNo, t.mount]))\n const marks: FigureRenderPart[] = []\n for (const p of places) {\n const slot = /^t(\\d+)_s\\d+$/.exec(p.id)\n if (!slot || !p.region) continue\n const [width, height, depth] = p.region.dimensions as [number, number, number]\n const down = mountOf.get(Number(slot[1])) === 'HANG'\n marks.push({\n id: `${SLOT_MARK}:${p.id}`,\n shape: {\n provider: 'extrude',\n dimensions: { width, height, depth },\n extrusion: { axis: 'y', section: { kind: 'rectangle', size: { x: width, z: depth } }, start: down ? -height : 0, end: down ? 0 : height }\n },\n pose: p.pose,\n material: { token: SLOT_MARK, transparent: true }\n })\n }\n return marks\n}\n"]}
|
|
1
|
+
{"version":3,"file":"slot-layout-host.js","sourceRoot":"","sources":["../../client/modeller/slot-layout-host.ts"],"names":[],"mappings":"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","sourcesContent":["/*\n * What the Figure modeller gives the shared slot layout editor (`@operato/slot-layout-editor`, the one fmsim hosts too),\n * and what it makes of the editor's result (ADR-0118). The editor edits tiers and slots; the modeller owns the anchors\n * -- a part's top or bottom face, named -- and sends the whole layout as one `set-slot-layout` command.\n *\n * A figure's released slot layout is the only one there is (ADR-0118 decision 8, user): no scene or run overrides it, so\n * this host offers no \"use default\" and no per-instance value.\n *\n * Kept free of Lit, i18n and the editor's element so node tests read it directly.\n */\nimport {\n figureShapeBoundsOf,\n figureSlotLayoutOf,\n figureSlotLayoutIssues,\n slotLayoutPreset,\n SLOT_LAYOUT_PRESET_KEYS,\n SLOT_LAYOUT_PRESET_PARAMS,\n type FigureAsset,\n type SlotLayout,\n type SlotPresetSize\n} from '@hatiolab/figure-model'\nimport type { FigureRenderPart } from './renderer.js'\n\nexport type SlotAnchorFace = 'top' | 'bottom'\nexport interface SlotAnchor {\n id: string\n part: string\n face: SlotAnchorFace\n}\n/** What the panel edits besides the tiers: the layout's name, what its slots are, and the anchors they stand on. */\nexport interface SlotLayoutForm {\n label: string\n role: 'seat' | 'grip'\n anchors: SlotAnchor[]\n}\n/** A layout problem as the editor shows it: a code, where, and its values. */\nexport interface SlotEditorIssue {\n code: string\n path: string\n params?: Record<string, string | number>\n}\n\ntype Body = { id: string; shape?: Parameters<typeof figureShapeBoundsOf>[0] }\n\n/** The figure's layout as the form and the layout, or a form to start one from on the selected part's top. */\nexport function slotLayoutFormOf(asset: FigureAsset, part: string): { form: SlotLayoutForm; layout?: SlotLayout } {\n const had = figureSlotLayoutOf(asset as never)\n if (had) return { form: { label: had.label, role: had.role, anchors: had.anchors.map(a => ({ ...a, face: a.face as SlotAnchorFace })) }, layout: had.layout }\n return { form: { label: '', role: 'seat', anchors: part ? [{ id: part, part, face: 'top' }] : [] } }\n}\n\n/** How big each anchor's face is, along the part's own X (width) and Z (depth): what the editor checks slots against. */\nexport function anchorFacesOf(anchors: readonly SlotAnchor[], geometry: readonly Body[]): Record<string, { width: number; depth: number }> {\n const out: Record<string, { width: number; depth: number }> = {}\n for (const a of anchors) {\n const body = geometry.find(g => g.id === a.part)\n if (!body?.shape) continue\n const b = figureShapeBoundsOf(body.shape)\n out[a.id] = { width: b.x.max - b.x.min, depth: b.z.max - b.z.min }\n }\n return out\n}\n\n/**\n * Where an author starts: the equipment presets (figure-model, ADR-0118 decision 8), laid out on this figure's anchors --\n * a one-anchor preset on the first, a twin fork on the first two. A single slot stands on a top and hangs from a bottom.\n * The editor's own controls then make it what the equipment is.\n */\nexport function slotPresetsOf(anchors: readonly SlotAnchor[]) {\n const first = anchors[0]\n const on = { ...(first ? { anchor: first.id } : {}), ...(anchors.length >= 2 ? { forks: [anchors[0]!.id, anchors[1]!.id] as [string, string] } : {}) }\n const mount = first?.face === 'bottom' ? ('HANG' as const) : ('ON' as const)\n return SLOT_LAYOUT_PRESET_KEYS.map(key => ({\n key,\n /* The editor names a preset and its values from their keys (@operato/slot-layout-editor's own words). */\n params: SLOT_LAYOUT_PRESET_PARAMS[key].map(p => ({ key: p.key, integer: p.integer })),\n build: (size: SlotPresetSize, params: Record<string, number>) => slotLayoutPreset(key, size, params, { ...on, mount })\n }))\n}\n\n/*\n * What figure-model asks beyond the editor's own checks: every slot names the types it takes (ADR-0118 decision 5) -- the\n * editor's \"any type\" is a board's, not a figure's. The kernel's own check (`figureSlotLayoutIssues`, the one a\n * placement's override is held to as well), said before Apply rather than refused after it; the editor already shows the\n * common findings, so only the figure's own are added.\n */\nexport function figureSlotIssues(layout: SlotLayout, anchors: readonly string[] = layout.tiers.map(t => t.anchorId)): SlotEditorIssue[] {\n return figureSlotLayoutIssues(layout, anchors).filter(issue => issue.code === 'ACCEPTS_REQUIRED')\n}\n\n/** The command the panel sends: the whole layout, its anchors and its name, as one step of the history. */\nexport function slotLayoutCommandOf(form: SlotLayoutForm, layout: SlotLayout, fallbackLabel: string) {\n return {\n kind: 'set-slot-layout' as const,\n label: form.label.trim() || fallbackLabel,\n role: form.role,\n anchors: form.anchors.map(a => ({ id: a.id.trim(), part: a.part, face: a.face })),\n layout: structuredClone(layout)\n }\n}\n\n/** A new anchor's id: the part's, or the part's with a number when that is taken. */\nexport function anchorIdFor(part: string, taken: readonly string[]): string {\n if (!taken.includes(part)) return part\n let n = 2\n while (taken.includes(`${part}_${n}`)) n++\n return `${part}_${n}`\n}\n\n/* The token the canvas draws slots in: translucent, never picked, never saved. */\nexport const SLOT_MARK = '__slot'\n\ntype Evaluated = { id: string; pose: { r: number[][]; t: number[] }; region: { dimensions: number[] } | null }\n\n/**\n * The unfolded slots as boxes the canvas draws (ADR-0118 decision 4): each as big as what it allows, standing on its\n * place -- or hanging from it, for a tier that hangs things -- so an author sees where every slot of the rule falls.\n */\nexport function slotMarksOf(places: readonly Evaluated[], layout: SlotLayout | undefined) {\n if (!layout) return []\n const mountOf = new Map(layout.tiers.map(t => [t.tierNo, t.mount]))\n const marks: FigureRenderPart[] = []\n for (const p of places) {\n const slot = /^t(\\d+)_s\\d+$/.exec(p.id)\n if (!slot || !p.region) continue\n const [width, height, depth] = p.region.dimensions as [number, number, number]\n const down = mountOf.get(Number(slot[1])) === 'HANG'\n marks.push({\n id: `${SLOT_MARK}:${p.id}`,\n shape: {\n provider: 'extrude',\n dimensions: { width, height, depth },\n extrusion: { axis: 'y', section: { kind: 'rectangle', size: { x: width, z: depth } }, start: down ? -height : 0, end: down ? 0 : height }\n },\n pose: p.pose,\n material: { token: SLOT_MARK, transparent: true }\n })\n }\n return marks\n}\n"]}
|
|
@@ -13,15 +13,13 @@ export interface BodyFrame {
|
|
|
13
13
|
origin: THREE.Vector3;
|
|
14
14
|
}
|
|
15
15
|
export declare function frameOf(part: FigureRenderPart): BodyFrame | null;
|
|
16
|
-
/** Per axis of the body's own frame, the face a size drag keeps: 1 the low face, -1 the high face, 0 the centre. */
|
|
17
|
-
export type ScaleAnchor = Record<'x' | 'y' | 'z', -1 | 0 | 1>;
|
|
18
16
|
/**
|
|
19
|
-
* The component state that draws a body where figure-model put it.
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
17
|
+
* The component state that draws a body where figure-model put it. A part the author edits is `owned`: while its size
|
|
18
|
+
* is dragged the scene does not move it and tells the handle held (`scaleGrab`), and the modeller draws where
|
|
19
|
+
* figure-model's size function puts it, every frame (ADR-0140 4.4). Body x · y · z are the component's width · depth ·
|
|
20
|
+
* height, as the scene's axes are.
|
|
23
21
|
*/
|
|
24
|
-
export declare function componentOf(part: FigureRenderPart, palette: Record<string, string>, board: Board,
|
|
22
|
+
export declare function componentOf(part: FigureRenderPart, palette: Record<string, string>, board: Board, owned?: boolean): Record<string, unknown> | null;
|
|
25
23
|
/**
|
|
26
24
|
* What the gizmo did, in the inputs' terms: where the body's origin is now, how it is turned (degrees, rigid@1's
|
|
27
25
|
* order) and how much each of its own axes grew. Only what changed is given; a component the gizmo did not move gives
|
|
@@ -27,12 +27,12 @@ function colours(part, palette) {
|
|
|
27
27
|
return { color: palette[m.token] ?? '#9a9a9a', preset: m.preset, transparent: !!m.transparent, ...(glow ? { glow } : {}) };
|
|
28
28
|
}
|
|
29
29
|
/**
|
|
30
|
-
* The component state that draws a body where figure-model put it.
|
|
31
|
-
*
|
|
32
|
-
*
|
|
33
|
-
*
|
|
30
|
+
* The component state that draws a body where figure-model put it. A part the author edits is `owned`: while its size
|
|
31
|
+
* is dragged the scene does not move it and tells the handle held (`scaleGrab`), and the modeller draws where
|
|
32
|
+
* figure-model's size function puts it, every frame (ADR-0140 4.4). Body x · y · z are the component's width · depth ·
|
|
33
|
+
* height, as the scene's axes are.
|
|
34
34
|
*/
|
|
35
|
-
export function componentOf(part, palette, board,
|
|
35
|
+
export function componentOf(part, palette, board, owned = false) {
|
|
36
36
|
const frame = frameOf(part);
|
|
37
37
|
if (!frame)
|
|
38
38
|
return null;
|
|
@@ -55,7 +55,7 @@ export function componentOf(part, palette, board, anchor) {
|
|
|
55
55
|
rotationX: round(euler.x),
|
|
56
56
|
rotation: round(-euler.y),
|
|
57
57
|
rotationY: round(euler.z),
|
|
58
|
-
...(
|
|
58
|
+
...(owned ? { scalePlacement: 'owner' } : {})
|
|
59
59
|
};
|
|
60
60
|
}
|
|
61
61
|
const num = (v, fallback = 0) => (typeof v === 'number' && Number.isFinite(v) ? v : fallback);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"stage-model.js","sourceRoot":"","sources":["../../client/modeller/stage-model.ts"],"names":[],"mappings":"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","sourcesContent":["import * as THREE from 'three'\nimport { buildFigureGeometry } from '@hatiolab/things-scene'\n\nimport type { GizmoResult } from './gizmo.js'\nimport type { FigureRenderPart } from './renderer.js'\n\n/*\n * bodies <-> scene components, in one place.\n *\n * The modeller stands on a things-scene board in editing mode: each body figure-model evaluates is a\n * `figure-part` component, and what the scene's gizmo writes back comes here to become a change of the part's\n * inputs. The two vocabularies:\n *\n * (asset frame, mm, y up) scene component\n * ──────────────────────────────── ─────────────────────────────────────────────\n * body box extent x · y · z width · depth · height\n * body box centre x left + width/2 - board width/2\n * y zPos + depth/2\n * z top + height/2 - board height/2\n * body rotation (rigid@1, Rx·Ry·Rz) rotationX · -rotation · rotationY (radians; three 'XYZ')\n *\n * The box is the body's own bounding box in its local frame, so a turned body keeps its size and the gizmo's handles\n * sit on its faces. Its centre is not always the body's origin (a portal rises from its bottom), so a turn about the\n * centre moves the origin: the result gives the origin where the turned body puts it.\n */\n\nexport interface Board {\n width: number\n height: number\n}\n\nexport interface BodyFrame {\n /** The body's box: its centre in the body's own frame, and its extent. */\n centre: THREE.Vector3\n extent: THREE.Vector3\n rotation: THREE.Matrix4\n origin: THREE.Vector3\n}\n\nconst round = (n: number) => Math.round(n * 1e6) / 1e6\n\nexport function frameOf(part: FigureRenderPart): BodyFrame | null {\n /* The box things-scene's `figure-part` centres the body on: the same builder, measured the same way. */\n let built: THREE.BufferGeometry | undefined\n try {\n built = buildFigureGeometry(part.shape as never, part.segments) as THREE.BufferGeometry | undefined\n } catch {\n return null\n }\n if (!built?.getAttribute('position')) return null\n built.computeBoundingBox()\n const box = built.boundingBox!\n const unit = { centre: box.getCenter(new THREE.Vector3()), extent: box.getSize(new THREE.Vector3()) }\n built.dispose()\n const r = part.pose.r\n const rotation = new THREE.Matrix4().set(r[0]![0]!, r[0]![1]!, r[0]![2]!, 0, r[1]![0]!, r[1]![1]!, r[1]![2]!, 0, r[2]![0]!, r[2]![1]!, r[2]![2]!, 0, 0, 0, 0, 1)\n return { centre: unit.centre, extent: unit.extent, rotation, origin: new THREE.Vector3(...(part.pose.t as [number, number, number])) }\n}\n\n/** The colours a body is drawn in, from the palette the modeller resolved (the asset's, over which the theme wins). */\nfunction colours(part: FigureRenderPart, palette: Record<string, string>) {\n const m = part.material\n const glow = m.emissive?.on ? { color: palette[m.emissive.token] ?? palette[m.token] ?? '#9a9a9a', intensity: m.emissive.intensity } : undefined\n return { color: palette[m.token] ?? '#9a9a9a', preset: m.preset, transparent: !!m.transparent, ...(glow ? { glow } : {}) }\n}\n\n/** Per axis of the body's own frame, the face a size drag keeps: 1 the low face, -1 the high face, 0 the centre. */\nexport type ScaleAnchor = Record<'x' | 'y' | 'z', -1 | 0 | 1>\n\n/**\n * The component state that draws a body where figure-model put it. With `anchor` -- figure-model's\n * `figureScaleAnchorOf` for its part -- the scene's scale gizmo keeps that face while it is dragged, the face the model\n * keeps when the drag is written; without it the gizmo keeps the face across from the handle held, and the part jumped\n * on release (designer 2026-09-27). Body x · y · z are the component's width · depth · height, as the scene's axes are.\n */\nexport function componentOf(part: FigureRenderPart, palette: Record<string, string>, board: Board, anchor?: ScaleAnchor): Record<string, unknown> | null {\n const frame = frameOf(part)\n if (!frame) return null\n const { centre, extent, rotation, origin } = frame\n const world = centre.clone().applyMatrix4(rotation).add(origin)\n const euler = new THREE.Euler().setFromRotationMatrix(rotation, 'XYZ')\n const width = extent.x || 1,\n depth = extent.y || 1,\n height = extent.z || 1\n return {\n type: 'figure-part',\n name: part.id,\n shape: part.shape,\n ...(part.segments !== undefined ? { segments: part.segments } : {}),\n ...colours(part, palette),\n width: round(width),\n depth: round(depth),\n height: round(height),\n left: round(world.x + board.width / 2 - width / 2),\n top: round(world.z + board.height / 2 - height / 2),\n zPos: round(world.y - depth / 2),\n rotationX: round(euler.x),\n rotation: round(-euler.y),\n rotationY: round(euler.z),\n ...(anchor ? { scaleAnchor: { ...anchor } } : {})\n }\n}\n\nconst num = (v: unknown, fallback = 0) => (typeof v === 'number' && Number.isFinite(v) ? v : fallback)\n\n/**\n * What the gizmo did, in the inputs' terms: where the body's origin is now, how it is turned (degrees, rigid@1's\n * order) and how much each of its own axes grew. Only what changed is given; a component the gizmo did not move gives\n * nothing.\n */\nexport function gizmoResultOf(part: FigureRenderPart, after: Record<string, unknown>, board: Board): GizmoResult {\n const frame = frameOf(part)\n if (!frame) return {}\n const { centre, extent, rotation, origin } = frame\n const width = num(after.width, extent.x),\n depth = num(after.depth, extent.y),\n height = num(after.height, extent.z)\n const scale = new THREE.Vector3(width / (extent.x || 1), depth / (extent.y || 1), height / (extent.z || 1))\n const world = new THREE.Vector3(num(after.left) + width / 2 - board.width / 2, num(after.zPos) + depth / 2, num(after.top) + height / 2 - board.height / 2)\n const euler = new THREE.Euler(num(after.rotationX), -num(after.rotation), num(after.rotationY), 'XYZ')\n const turnedTo = new THREE.Matrix4().makeRotationFromEuler(euler)\n\n const before = new THREE.Quaternion().setFromRotationMatrix(rotation)\n const now = new THREE.Quaternion().setFromEuler(euler)\n const turned = before.angleTo(now) > 1e-4\n const sized = [scale.x, scale.y, scale.z].some(s => Math.abs(s - 1) > 1e-4)\n /* The origin that puts the (scaled, turned) box centre where the scene has it. */\n const newOrigin = world.clone().sub(centre.clone().multiply(scale).applyMatrix4(turnedTo))\n const moved = newOrigin.distanceTo(origin) > 0.5\n\n const result: GizmoResult = {}\n if (moved || turned) result.position = newOrigin.toArray() as [number, number, number]\n if (turned) result.rotation = [euler.x, euler.y, euler.z].map(THREE.MathUtils.radToDeg) as [number, number, number]\n if (sized) result.scale = scale.toArray() as [number, number, number]\n return result\n}\n\n/**\n * A drag as amounts, for a part whose place is worked out (`nudge-part`): how far its origin moved and how far each of\n * its angles turned (rigid@1's order, degrees). Nothing on an axis that did not change.\n */\nexport function nudgeOf(part: FigureRenderPart, result: GizmoResult): { by: Partial<Record<'x' | 'y' | 'z', number>>; turn: Partial<Record<'x' | 'y' | 'z', number>> } {\n const axes = ['x', 'y', 'z'] as const\n const by: Partial<Record<'x' | 'y' | 'z', number>> = {}\n const turn: Partial<Record<'x' | 'y' | 'z', number>> = {}\n if (result.position) axes.forEach((axis, i) => {\n const d = round(result.position![i]! - (part.pose.t[i] as number))\n if (Math.abs(d) > 1e-6) by[axis] = d\n })\n if (result.rotation) {\n const r = part.pose.r\n const now = new THREE.Euler().setFromRotationMatrix(new THREE.Matrix4().set(r[0]![0]!, r[0]![1]!, r[0]![2]!, 0, r[1]![0]!, r[1]![1]!, r[1]![2]!, 0, r[2]![0]!, r[2]![1]!, r[2]![2]!, 0, 0, 0, 0, 1), 'XYZ')\n const was: number[] = [now.x, now.y, now.z].map(radians => (radians * 180) / Math.PI)\n axes.forEach((axis, i) => {\n const d = round(result.rotation![i]! - was[i]!)\n if (Math.abs(d) > 1e-6) turn[axis] = d\n })\n }\n return { by, turn }\n}\n\n/** The keys of `next` whose values differ from `current` -- only those are set, so the scene raises no echo. */\nexport function changedKeys(current: Record<string, unknown>, next: Record<string, unknown>): Record<string, unknown> | null {\n const diff: Record<string, unknown> = {}\n for (const [key, value] of Object.entries(next)) {\n if (key === 'type') continue\n const was = current[key]\n const same = typeof value === 'object' && value !== null ? JSON.stringify(was) === JSON.stringify(value) : was === value\n if (!same) diff[key] = value\n }\n return Object.keys(diff).length ? diff : null\n}\n\n/** A board wide and deep enough for the figure, with room around it; its size only grows while a figure is edited. */\nexport function boardFor(parts: readonly FigureRenderPart[], at: Board & { depth?: number } = { width: 0, height: 0 }): Board & { depth: number } {\n const box = new THREE.Box3()\n for (const part of parts) {\n const frame = frameOf(part)\n if (!frame) continue\n const half = frame.extent.clone().multiplyScalar(0.5)\n const corners = [-1, 1].flatMap(x => [-1, 1].flatMap(y => [-1, 1].map(z => new THREE.Vector3(x * half.x, y * half.y, z * half.z))))\n for (const corner of corners) box.expandByPoint(corner.add(frame.centre).applyMatrix4(frame.rotation).add(frame.origin))\n }\n const size = box.isEmpty() ? new THREE.Vector3(1000, 1000, 1000) : box.getSize(new THREE.Vector3())\n const reach = (axis: 'x' | 'z') => 2 * Math.max(Math.abs(box.isEmpty() ? 500 : box.min[axis]), Math.abs(box.isEmpty() ? 500 : box.max[axis]))\n return {\n width: Math.max(at.width, Math.ceil(reach('x') * 1.2), 200),\n height: Math.max(at.height, Math.ceil(reach('z') * 1.2), 200),\n /* Only grows, as the plan does: a raised arm made the board taller than it was, and a new board lost the camera. */\n depth: Math.max(at.depth ?? 0, Math.ceil(size.y * 1.1), 200)\n }\n}\n\n/**\n * Whether the figure's reach has changed so far since the view was last fitted that the camera should fit it again:\n * more than twice, or less than half, on any axis (first 15 minutes, 2026-10-16: a 100 mm box typed to 3000 × 800 × 600\n * put the camera inside it, and the author saw grey until pressing 「화면에 맞추기」). A drag that nudges a part does not\n * move the camera.\n */\nexport function needsRefit(fitted: (Board & { depth: number }) | undefined, now: Board & { depth: number }): boolean {\n if (!fitted) return false\n return (['width', 'height', 'depth'] as const).some(key => now[key] > fitted[key] * 2 || now[key] < fitted[key] / 2)\n}\n\n/**\n * A body's placement as its fields would read it: its origin in mm and its turn in degrees (rigid@1's X·Y·Z order, as\n * `componentOf` reads it). For a field a rule sets -- a fastened part's height, a turn its joint fixes -- the screen shows\n * this number read-only rather than a blank (designer 2026-09-27).\n */\nexport function placementOf(part: FigureRenderPart): { position: [number, number, number]; rotation: [number, number, number] } {\n const r = part.pose.r\n const m = new THREE.Matrix4().set(r[0]![0]!, r[0]![1]!, r[0]![2]!, 0, r[1]![0]!, r[1]![1]!, r[1]![2]!, 0, r[2]![0]!, r[2]![1]!, r[2]![2]!, 0, 0, 0, 0, 1)\n const e = new THREE.Euler().setFromRotationMatrix(m, 'XYZ')\n const deg = (v: number) => Math.round(THREE.MathUtils.radToDeg(v) * 10) / 10 || 0\n return { position: part.pose.t.map(round) as [number, number, number], rotation: [deg(e.x), deg(e.y), deg(e.z)] }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"stage-model.js","sourceRoot":"","sources":["../../client/modeller/stage-model.ts"],"names":[],"mappings":"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","sourcesContent":["import * as THREE from 'three'\nimport { buildFigureGeometry } from '@hatiolab/things-scene'\n\nimport type { GizmoResult } from './gizmo.js'\nimport type { FigureRenderPart } from './renderer.js'\n\n/*\n * bodies <-> scene components, in one place.\n *\n * The modeller stands on a things-scene board in editing mode: each body figure-model evaluates is a\n * `figure-part` component, and what the scene's gizmo writes back comes here to become a change of the part's\n * inputs. The two vocabularies:\n *\n * (asset frame, mm, y up) scene component\n * ──────────────────────────────── ─────────────────────────────────────────────\n * body box extent x · y · z width · depth · height\n * body box centre x left + width/2 - board width/2\n * y zPos + depth/2\n * z top + height/2 - board height/2\n * body rotation (rigid@1, Rx·Ry·Rz) rotationX · -rotation · rotationY (radians; three 'XYZ')\n *\n * The box is the body's own bounding box in its local frame, so a turned body keeps its size and the gizmo's handles\n * sit on its faces. Its centre is not always the body's origin (a portal rises from its bottom), so a turn about the\n * centre moves the origin: the result gives the origin where the turned body puts it.\n */\n\nexport interface Board {\n width: number\n height: number\n}\n\nexport interface BodyFrame {\n /** The body's box: its centre in the body's own frame, and its extent. */\n centre: THREE.Vector3\n extent: THREE.Vector3\n rotation: THREE.Matrix4\n origin: THREE.Vector3\n}\n\nconst round = (n: number) => Math.round(n * 1e6) / 1e6\n\nexport function frameOf(part: FigureRenderPart): BodyFrame | null {\n /* The box things-scene's `figure-part` centres the body on: the same builder, measured the same way. */\n let built: THREE.BufferGeometry | undefined\n try {\n built = buildFigureGeometry(part.shape as never, part.segments) as THREE.BufferGeometry | undefined\n } catch {\n return null\n }\n if (!built?.getAttribute('position')) return null\n built.computeBoundingBox()\n const box = built.boundingBox!\n const unit = { centre: box.getCenter(new THREE.Vector3()), extent: box.getSize(new THREE.Vector3()) }\n built.dispose()\n const r = part.pose.r\n const rotation = new THREE.Matrix4().set(r[0]![0]!, r[0]![1]!, r[0]![2]!, 0, r[1]![0]!, r[1]![1]!, r[1]![2]!, 0, r[2]![0]!, r[2]![1]!, r[2]![2]!, 0, 0, 0, 0, 1)\n return { centre: unit.centre, extent: unit.extent, rotation, origin: new THREE.Vector3(...(part.pose.t as [number, number, number])) }\n}\n\n/** The colours a body is drawn in, from the palette the modeller resolved (the asset's, over which the theme wins). */\nfunction colours(part: FigureRenderPart, palette: Record<string, string>) {\n const m = part.material\n const glow = m.emissive?.on ? { color: palette[m.emissive.token] ?? palette[m.token] ?? '#9a9a9a', intensity: m.emissive.intensity } : undefined\n return { color: palette[m.token] ?? '#9a9a9a', preset: m.preset, transparent: !!m.transparent, ...(glow ? { glow } : {}) }\n}\n\n/**\n * The component state that draws a body where figure-model put it. A part the author edits is `owned`: while its size\n * is dragged the scene does not move it and tells the handle held (`scaleGrab`), and the modeller draws where\n * figure-model's size function puts it, every frame (ADR-0140 4.4). Body x · y · z are the component's width · depth ·\n * height, as the scene's axes are.\n */\nexport function componentOf(part: FigureRenderPart, palette: Record<string, string>, board: Board, owned = false): Record<string, unknown> | null {\n const frame = frameOf(part)\n if (!frame) return null\n const { centre, extent, rotation, origin } = frame\n const world = centre.clone().applyMatrix4(rotation).add(origin)\n const euler = new THREE.Euler().setFromRotationMatrix(rotation, 'XYZ')\n const width = extent.x || 1,\n depth = extent.y || 1,\n height = extent.z || 1\n return {\n type: 'figure-part',\n name: part.id,\n shape: part.shape,\n ...(part.segments !== undefined ? { segments: part.segments } : {}),\n ...colours(part, palette),\n width: round(width),\n depth: round(depth),\n height: round(height),\n left: round(world.x + board.width / 2 - width / 2),\n top: round(world.z + board.height / 2 - height / 2),\n zPos: round(world.y - depth / 2),\n rotationX: round(euler.x),\n rotation: round(-euler.y),\n rotationY: round(euler.z),\n ...(owned ? { scalePlacement: 'owner' } : {})\n }\n}\n\nconst num = (v: unknown, fallback = 0) => (typeof v === 'number' && Number.isFinite(v) ? v : fallback)\n\n/**\n * What the gizmo did, in the inputs' terms: where the body's origin is now, how it is turned (degrees, rigid@1's\n * order) and how much each of its own axes grew. Only what changed is given; a component the gizmo did not move gives\n * nothing.\n */\nexport function gizmoResultOf(part: FigureRenderPart, after: Record<string, unknown>, board: Board): GizmoResult {\n const frame = frameOf(part)\n if (!frame) return {}\n const { centre, extent, rotation, origin } = frame\n const width = num(after.width, extent.x),\n depth = num(after.depth, extent.y),\n height = num(after.height, extent.z)\n const scale = new THREE.Vector3(width / (extent.x || 1), depth / (extent.y || 1), height / (extent.z || 1))\n const world = new THREE.Vector3(num(after.left) + width / 2 - board.width / 2, num(after.zPos) + depth / 2, num(after.top) + height / 2 - board.height / 2)\n const euler = new THREE.Euler(num(after.rotationX), -num(after.rotation), num(after.rotationY), 'XYZ')\n const turnedTo = new THREE.Matrix4().makeRotationFromEuler(euler)\n\n const before = new THREE.Quaternion().setFromRotationMatrix(rotation)\n const now = new THREE.Quaternion().setFromEuler(euler)\n const turned = before.angleTo(now) > 1e-4\n const sized = [scale.x, scale.y, scale.z].some(s => Math.abs(s - 1) > 1e-4)\n /* The origin that puts the (scaled, turned) box centre where the scene has it. */\n const newOrigin = world.clone().sub(centre.clone().multiply(scale).applyMatrix4(turnedTo))\n const moved = newOrigin.distanceTo(origin) > 0.5\n\n const result: GizmoResult = {}\n if (moved || turned) result.position = newOrigin.toArray() as [number, number, number]\n if (turned) result.rotation = [euler.x, euler.y, euler.z].map(THREE.MathUtils.radToDeg) as [number, number, number]\n if (sized) result.scale = scale.toArray() as [number, number, number]\n return result\n}\n\n/**\n * A drag as amounts, for a part whose place is worked out (`nudge-part`): how far its origin moved and how far each of\n * its angles turned (rigid@1's order, degrees). Nothing on an axis that did not change.\n */\nexport function nudgeOf(part: FigureRenderPart, result: GizmoResult): { by: Partial<Record<'x' | 'y' | 'z', number>>; turn: Partial<Record<'x' | 'y' | 'z', number>> } {\n const axes = ['x', 'y', 'z'] as const\n const by: Partial<Record<'x' | 'y' | 'z', number>> = {}\n const turn: Partial<Record<'x' | 'y' | 'z', number>> = {}\n if (result.position) axes.forEach((axis, i) => {\n const d = round(result.position![i]! - (part.pose.t[i] as number))\n if (Math.abs(d) > 1e-6) by[axis] = d\n })\n if (result.rotation) {\n const r = part.pose.r\n const now = new THREE.Euler().setFromRotationMatrix(new THREE.Matrix4().set(r[0]![0]!, r[0]![1]!, r[0]![2]!, 0, r[1]![0]!, r[1]![1]!, r[1]![2]!, 0, r[2]![0]!, r[2]![1]!, r[2]![2]!, 0, 0, 0, 0, 1), 'XYZ')\n const was: number[] = [now.x, now.y, now.z].map(radians => (radians * 180) / Math.PI)\n axes.forEach((axis, i) => {\n const d = round(result.rotation![i]! - was[i]!)\n if (Math.abs(d) > 1e-6) turn[axis] = d\n })\n }\n return { by, turn }\n}\n\n/** The keys of `next` whose values differ from `current` -- only those are set, so the scene raises no echo. */\nexport function changedKeys(current: Record<string, unknown>, next: Record<string, unknown>): Record<string, unknown> | null {\n const diff: Record<string, unknown> = {}\n for (const [key, value] of Object.entries(next)) {\n if (key === 'type') continue\n const was = current[key]\n const same = typeof value === 'object' && value !== null ? JSON.stringify(was) === JSON.stringify(value) : was === value\n if (!same) diff[key] = value\n }\n return Object.keys(diff).length ? diff : null\n}\n\n/** A board wide and deep enough for the figure, with room around it; its size only grows while a figure is edited. */\nexport function boardFor(parts: readonly FigureRenderPart[], at: Board & { depth?: number } = { width: 0, height: 0 }): Board & { depth: number } {\n const box = new THREE.Box3()\n for (const part of parts) {\n const frame = frameOf(part)\n if (!frame) continue\n const half = frame.extent.clone().multiplyScalar(0.5)\n const corners = [-1, 1].flatMap(x => [-1, 1].flatMap(y => [-1, 1].map(z => new THREE.Vector3(x * half.x, y * half.y, z * half.z))))\n for (const corner of corners) box.expandByPoint(corner.add(frame.centre).applyMatrix4(frame.rotation).add(frame.origin))\n }\n const size = box.isEmpty() ? new THREE.Vector3(1000, 1000, 1000) : box.getSize(new THREE.Vector3())\n const reach = (axis: 'x' | 'z') => 2 * Math.max(Math.abs(box.isEmpty() ? 500 : box.min[axis]), Math.abs(box.isEmpty() ? 500 : box.max[axis]))\n return {\n width: Math.max(at.width, Math.ceil(reach('x') * 1.2), 200),\n height: Math.max(at.height, Math.ceil(reach('z') * 1.2), 200),\n /* Only grows, as the plan does: a raised arm made the board taller than it was, and a new board lost the camera. */\n depth: Math.max(at.depth ?? 0, Math.ceil(size.y * 1.1), 200)\n }\n}\n\n/**\n * Whether the figure's reach has changed so far since the view was last fitted that the camera should fit it again:\n * more than twice, or less than half, on any axis (first 15 minutes, 2026-10-16: a 100 mm box typed to 3000 × 800 × 600\n * put the camera inside it, and the author saw grey until pressing 「화면에 맞추기」). A drag that nudges a part does not\n * move the camera.\n */\nexport function needsRefit(fitted: (Board & { depth: number }) | undefined, now: Board & { depth: number }): boolean {\n if (!fitted) return false\n return (['width', 'height', 'depth'] as const).some(key => now[key] > fitted[key] * 2 || now[key] < fitted[key] / 2)\n}\n\n/**\n * A body's placement as its fields would read it: its origin in mm and its turn in degrees (rigid@1's X·Y·Z order, as\n * `componentOf` reads it). For a field a rule sets -- a fastened part's height, a turn its joint fixes -- the screen shows\n * this number read-only rather than a blank (designer 2026-09-27).\n */\nexport function placementOf(part: FigureRenderPart): { position: [number, number, number]; rotation: [number, number, number] } {\n const r = part.pose.r\n const m = new THREE.Matrix4().set(r[0]![0]!, r[0]![1]!, r[0]![2]!, 0, r[1]![0]!, r[1]![1]!, r[1]![2]!, 0, r[2]![0]!, r[2]![1]!, r[2]![2]!, 0, 0, 0, 0, 1)\n const e = new THREE.Euler().setFromRotationMatrix(m, 'XYZ')\n const deg = (v: number) => Math.round(THREE.MathUtils.radToDeg(v) * 10) / 10 || 0\n return { position: part.pose.t.map(round) as [number, number, number], rotation: [deg(e.x), deg(e.y), deg(e.z)] }\n}\n"]}
|
|
@@ -39,8 +39,6 @@ export declare class FigureModellerPage extends PageView {
|
|
|
39
39
|
private commandError;
|
|
40
40
|
/** What the verdict says blocks release now, handed to the editor's bar. */
|
|
41
41
|
private releaseBlockers;
|
|
42
|
-
/** The verdict's count, handed to the editor's verdict tab. */
|
|
43
|
-
private instances?;
|
|
44
42
|
private budget?;
|
|
45
43
|
private wasDirty;
|
|
46
44
|
private titled?;
|
|
@@ -543,7 +543,7 @@ let FigureModellerPage = class FigureModellerPage extends PageView {
|
|
|
543
543
|
return html `<p role="alert" class="error">${this.error}</p>`;
|
|
544
544
|
const view = this.session.read();
|
|
545
545
|
/* A new figure's third way to start: the app's assistant dock, with a request put in its input for the author to finish and send (B, U04). */
|
|
546
|
-
return html `<figure-editor .session=${this.session} .releaseState=${this.row} .releaseBlockers=${this.releaseBlockers} .templates=${this.templates} .guideOf=${this.guideOf} .thumbnailOf=${this.thumbnailOf} .firstSave=${this.askFirstSave} .revision=${this.revision} .
|
|
546
|
+
return html `<figure-editor .session=${this.session} .releaseState=${this.row} .releaseBlockers=${this.releaseBlockers} .templates=${this.templates} .guideOf=${this.guideOf} .thumbnailOf=${this.thumbnailOf} .firstSave=${this.askFirstSave} .revision=${this.revision} .budget=${this.budget} aiDraft @ask-ai-draft=${() => askAssistant({ draft: i18next.t('figure.text.ai-draft-request') })} @changed=${this.changed}>
|
|
547
547
|
${this.commandError ? html `<p slot="notice" fit-error role="alert">${this.commandError}</p>` : ''}
|
|
548
548
|
<figure-properties
|
|
549
549
|
slot="figure"
|
|
@@ -573,7 +573,6 @@ let FigureModellerPage = class FigureModellerPage extends PageView {
|
|
|
573
573
|
.figureId=${view.id}
|
|
574
574
|
.figureType=${this.row.type}
|
|
575
575
|
@capacity-changed=${(event) => {
|
|
576
|
-
this.instances = event.detail.instances;
|
|
577
576
|
this.budget = event.detail.budget;
|
|
578
577
|
}}
|
|
579
578
|
@fit-base-to-parts=${this.fitToParts}
|
|
@@ -628,10 +627,6 @@ __decorate([
|
|
|
628
627
|
state(),
|
|
629
628
|
__metadata("design:type", Array)
|
|
630
629
|
], FigureModellerPage.prototype, "releaseBlockers", void 0);
|
|
631
|
-
__decorate([
|
|
632
|
-
state(),
|
|
633
|
-
__metadata("design:type", Number)
|
|
634
|
-
], FigureModellerPage.prototype, "instances", void 0);
|
|
635
630
|
__decorate([
|
|
636
631
|
state(),
|
|
637
632
|
__metadata("design:type", Object)
|