@things-factory/figure-ui 10.1.200 → 10.1.201
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/editor.ts +7 -3
- package/client/modeller/fasten-form.ts +18 -35
- package/client/modeller/fasten-geometry.ts +67 -115
- package/client/modeller/figure-fasten-dialog.ts +4 -12
- package/client/modeller/figure-links.ts +6 -7
- package/client/modeller/joint-drag.ts +5 -5
- package/client/modeller/links.ts +35 -99
- package/client/modeller/refusals.ts +2 -6
- package/dist-client/modeller/editor.js +7 -2
- package/dist-client/modeller/editor.js.map +1 -1
- package/dist-client/modeller/fasten-form.d.ts +5 -8
- package/dist-client/modeller/fasten-form.js +16 -28
- package/dist-client/modeller/fasten-form.js.map +1 -1
- package/dist-client/modeller/fasten-geometry.d.ts +20 -19
- package/dist-client/modeller/fasten-geometry.js +54 -113
- package/dist-client/modeller/fasten-geometry.js.map +1 -1
- package/dist-client/modeller/figure-fasten-dialog.js +4 -12
- package/dist-client/modeller/figure-fasten-dialog.js.map +1 -1
- package/dist-client/modeller/figure-links.d.ts +1 -1
- package/dist-client/modeller/figure-links.js +6 -7
- package/dist-client/modeller/figure-links.js.map +1 -1
- package/dist-client/modeller/joint-drag.js +5 -5
- package/dist-client/modeller/joint-drag.js.map +1 -1
- package/dist-client/modeller/links.d.ts +19 -26
- package/dist-client/modeller/links.js +36 -94
- package/dist-client/modeller/links.js.map +1 -1
- package/dist-client/modeller/refusals.d.ts +1 -1
- package/dist-client/modeller/refusals.js +2 -6
- package/dist-client/modeller/refusals.js.map +1 -1
- package/dist-client/tsconfig.tsbuildinfo +1 -1
- package/package.json +6 -6
- package/test/ai-proposal.test.ts +1 -1
- package/test/browser/acceptance-page.js +11 -11
- package/test/browser/detail-page.js +1 -1
- package/test/browser/detail-tabs-page.js +1 -1
- package/test/browser/editing-page.js +1 -1
- package/test/browser/fix-alignment.check.mjs +3 -3
- package/test/browser/links.check.mjs +20 -8
- package/test/browser/modeller-page.js +3 -3
- package/test/browser/part-ids.check.mjs +2 -2
- package/test/browser/parts-page.js +2 -2
- package/test/browser/product-page.check.mjs +3 -3
- package/test/browser/product-page.js +1 -1
- package/test/browser/row-preview.check.mjs +2 -2
- package/test/browser/screen-page.js +3 -3
- package/test/browser/section-page.js +3 -3
- package/test/browser/section.check.mjs +4 -4
- package/test/clip-ai-proposal.test.ts +1 -1
- package/test/clip-consent.test.ts +1 -1
- package/test/command-preview.test.ts +8 -8
- package/test/face-mapping.test.ts +2 -2
- package/test/fasten-drawing.test.ts +14 -2
- package/test/fasten-form.test.ts +11 -3
- package/test/fasten-geometry.test.ts +22 -31
- package/test/fix-alignment.test.ts +16 -4
- package/test/gizmo.test.ts +2 -2
- package/test/joint-drag.test.ts +13 -2
- package/test/joint-fan.test.ts +1 -1
- package/test/joint-frames.test.ts +45 -23
- package/test/joints.ts +1 -1
- package/test/links.test.ts +68 -68
- package/test/live.test.ts +2 -2
- package/test/preview-size.test.ts +1 -1
- package/test/refusals.test.ts +18 -20
- package/test/resize-with-placement.test.ts +6 -6
- package/test/revision.test.ts +4 -5
- package/test/section-panel.test.ts +1 -1
- package/translations/en.json +9 -11
- package/translations/es.json +9 -11
- package/translations/ja.json +9 -11
- package/translations/ko.json +9 -11
- package/translations/ms.json +9 -11
- package/translations/zh.json +9 -11
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@things-factory/figure-ui",
|
|
3
|
-
"version": "10.1.
|
|
3
|
+
"version": "10.1.201",
|
|
4
4
|
"publishConfig": {
|
|
5
5
|
"access": "public",
|
|
6
6
|
"@things-factory:registry": "https://registry.npmjs.org"
|
|
@@ -27,8 +27,8 @@
|
|
|
27
27
|
"clean": "npm run clean:server && npm run clean:client"
|
|
28
28
|
},
|
|
29
29
|
"dependencies": {
|
|
30
|
-
"@hatiolab/figure-model": "^0.
|
|
31
|
-
"@hatiolab/things-scene": "^10.1.
|
|
30
|
+
"@hatiolab/figure-model": "^0.9.3",
|
|
31
|
+
"@hatiolab/things-scene": "^10.1.95",
|
|
32
32
|
"@material/web": "^2.0.0",
|
|
33
33
|
"@operato/data-grist": "^10.29.43",
|
|
34
34
|
"@operato/graphql": "^10.29.43",
|
|
@@ -43,10 +43,10 @@
|
|
|
43
43
|
"@operato/styles": "^10.0.0",
|
|
44
44
|
"@operato/utils": "^10.29.43",
|
|
45
45
|
"@things-factory/ai-assistant": "^10.1.198",
|
|
46
|
-
"@things-factory/figure-service": "^10.1.
|
|
47
|
-
"@things-factory/figure-viewer": "^10.1.
|
|
46
|
+
"@things-factory/figure-service": "^10.1.201",
|
|
47
|
+
"@things-factory/figure-viewer": "^10.1.201",
|
|
48
48
|
"@things-factory/setting-base": "^10.1.198",
|
|
49
49
|
"three": "^0.185.1"
|
|
50
50
|
},
|
|
51
|
-
"gitHead": "
|
|
51
|
+
"gitHead": "6d7a1ae96c2e21bc95b9913b0b32f9ad44c7f87a"
|
|
52
52
|
}
|
package/test/ai-proposal.test.ts
CHANGED
|
@@ -26,7 +26,7 @@ const store = {
|
|
|
26
26
|
}
|
|
27
27
|
const steps = [
|
|
28
28
|
{ kind: 'add-part', part: { id: 'lid', kind: 'box', dimensions: { width: 100, height: 10, depth: 100 } } },
|
|
29
|
-
{ kind: 'attach', part: 'lid',
|
|
29
|
+
{ kind: 'attach', part: 'lid', to: { part: 'body', face: 'top' } },
|
|
30
30
|
{ kind: 'rename', name: 'Box with lid' }
|
|
31
31
|
] as any[]
|
|
32
32
|
|
|
@@ -53,7 +53,7 @@ export const MODELS = {
|
|
|
53
53
|
a.palette = { ...a.palette, ...PALETTE }
|
|
54
54
|
a = addFigurePrimitive(a, { id: 'wedge', kind: 'polygon', dimensions: { height: 200 }, points: [{ x: -300, z: -200 }, { x: 300, z: -200 }, { x: 0, z: 250 }], position: { x: 0, y: 100, z: 0 } })
|
|
55
55
|
a = addFigureBox(a, { id: 'cap', size: { x: 100, y: 20, z: 100 }, position: { x: 0, y: 0, z: 0 } })
|
|
56
|
-
a = applyFigureAuthoring(a, { kind: 'attach', part: 'cap',
|
|
56
|
+
a = applyFigureAuthoring(a, { kind: 'attach', part: 'cap', to: { part: 'wedge', face: 'top' } })
|
|
57
57
|
return serializeFigureAsset(a)
|
|
58
58
|
},
|
|
59
59
|
/* A lid fastened to the top of a bin standing on the floor: the fastening drawn and dragged (user 2026-10-01). */
|
|
@@ -61,9 +61,9 @@ export const MODELS = {
|
|
|
61
61
|
let a = createFigureAsset('Lid on bin')
|
|
62
62
|
a.palette = { ...a.palette, ...PALETTE }
|
|
63
63
|
a = addFigureBox(a, { id: 'bin', size: { x: 600, y: 300, z: 400 }, position: { x: 0, y: 150, z: 0 } })
|
|
64
|
-
a = applyFigureAuthoring(a, { kind: 'attach', part: 'bin',
|
|
64
|
+
a = applyFigureAuthoring(a, { kind: 'attach', part: 'bin', to: { plane: 'mounting-plane' } })
|
|
65
65
|
a = addFigureBox(a, { id: 'lid', size: { x: 300, y: 20, z: 200 }, position: { x: 0, y: 0, z: 0 } })
|
|
66
|
-
a = applyFigureAuthoring(a, { kind: 'attach', part: 'lid',
|
|
66
|
+
a = applyFigureAuthoring(a, { kind: 'attach', part: 'lid', to: { part: 'bin', face: 'top' } })
|
|
67
67
|
return serializeFigureAsset(a)
|
|
68
68
|
},
|
|
69
69
|
/* A divider standing on a tote's inside floor: opening the bottom asks where the divider goes (ADR-0100 A8). */
|
|
@@ -71,10 +71,10 @@ export const MODELS = {
|
|
|
71
71
|
let a = createFigureAsset('Divider in tote')
|
|
72
72
|
a.palette = { ...a.palette, ...PALETTE }
|
|
73
73
|
a = addFigureBox(a, { id: 'bin', size: { x: 600, y: 300, z: 400 }, position: { x: 0, y: 150, z: 0 } })
|
|
74
|
-
a = applyFigureAuthoring(a, { kind: 'attach', part: 'bin',
|
|
74
|
+
a = applyFigureAuthoring(a, { kind: 'attach', part: 'bin', to: { plane: 'mounting-plane' } })
|
|
75
75
|
a = applyFigureAuthoring(a, { kind: 'set-cavity', part: 'bin', cavity: { wall: 10, start: { closed: 15 }, end: 'open' } })
|
|
76
76
|
a = addFigureBox(a, { id: 'divider', size: { x: 10, y: 200, z: 380 }, position: { x: 0, y: 0, z: 0 } })
|
|
77
|
-
a = applyFigureAuthoring(a, { kind: 'attach', part: 'divider',
|
|
77
|
+
a = applyFigureAuthoring(a, { kind: 'attach', part: 'divider', to: { part: 'bin', face: 'inside-bottom' } })
|
|
78
78
|
return serializeFigureAsset(a)
|
|
79
79
|
},
|
|
80
80
|
/* A box and a drum: rounded corners and an inside from the properties tab (ADR-0100 stage 1). */
|
|
@@ -110,7 +110,7 @@ export const MODELS = {
|
|
|
110
110
|
a = addFigureBox(a, { id: 'frame', size: { x: 2000, y: 100, z: 200 }, position: { x: 0, y: 50, z: 0 } })
|
|
111
111
|
for (const [id, x] of [['left', -500], ['right', 500]]) {
|
|
112
112
|
a = addFigureBox(a, { id, size: { x: 900, y: 1800, z: 40 }, position: { x, y: 1000, z: 0 } })
|
|
113
|
-
a = applyFigureAuthoring(a, { kind: 'attach', part: id,
|
|
113
|
+
a = applyFigureAuthoring(a, { kind: 'attach', part: id, to: { part: 'frame', face: 'top' } })
|
|
114
114
|
const j = a.joints.find(k => k.body1.part === id)
|
|
115
115
|
a = applyFigureAuthoring(a, { kind: 'set-joint', joint: { ...j, type: 'revolute', axis: 'Y', state: { id: `${id}-open` } } })
|
|
116
116
|
a = editFigurePart(a, { kind: 'set-driver', state: `${id}-open`, clip: `${id}-swing`, duration: 2, keys: [{ seconds: 0, value: 0 }, { seconds: 2, value: 80 }] })
|
|
@@ -123,7 +123,7 @@ export const MODELS = {
|
|
|
123
123
|
a.palette = { ...a.palette, ...PALETTE }
|
|
124
124
|
a = addFigureBox(a, { id: 'frame', size: { x: 2000, y: 100, z: 600 }, position: { x: 0, y: 400, z: 0 } })
|
|
125
125
|
a = addFigureBox(a, { id: 'roller', size: { x: 60, y: 60, z: 560 }, position: { x: 0, y: 480, z: 0 } })
|
|
126
|
-
a = applyFigureAuthoring(a, { kind: 'attach', part: 'roller',
|
|
126
|
+
a = applyFigureAuthoring(a, { kind: 'attach', part: 'roller', to: { part: 'frame', face: 'top' } })
|
|
127
127
|
return serializeFigureAsset(a)
|
|
128
128
|
},
|
|
129
129
|
/* A device fastened on a bench top 300 mm off centre: the top narrowed on the screen brings it past the edge (C, scenario 1, Q3). */
|
|
@@ -133,8 +133,8 @@ export const MODELS = {
|
|
|
133
133
|
a = addFigureBox(a, { id: 'leg', size: { x: 60, y: 700, z: 60 }, position: { x: 0, y: 350, z: 0 } })
|
|
134
134
|
a = addFigureBox(a, { id: 'top', size: { x: 1200, y: 40, z: 600 }, position: { x: 0, y: 720, z: 0 } })
|
|
135
135
|
a = addFigureBox(a, { id: 'device', size: { x: 100, y: 100, z: 100 }, position: { x: 300, y: 790, z: 100 } })
|
|
136
|
-
a = applyFigureAuthoring(a, { kind: 'attach', part: 'top',
|
|
137
|
-
a = applyFigureAuthoring(a, { kind: 'attach', part: 'device',
|
|
136
|
+
a = applyFigureAuthoring(a, { kind: 'attach', part: 'top', to: { part: 'leg', face: 'top' } })
|
|
137
|
+
a = applyFigureAuthoring(a, { kind: 'attach', part: 'device', to: { part: 'top', face: 'top' }, align: { x: { mm: 300 }, z: { mm: 100 } } })
|
|
138
138
|
return serializeFigureAsset(a)
|
|
139
139
|
},
|
|
140
140
|
/* A door leaf fastened to its frame, not moving yet: its motion is set on the screen (C, scenario 3). */
|
|
@@ -144,8 +144,8 @@ export const MODELS = {
|
|
|
144
144
|
a = addFigureBox(a, { id: 'frame', size: { x: 1200, y: 100, z: 200 }, position: { x: 0, y: 50, z: 0 } })
|
|
145
145
|
a = addFigureBox(a, { id: 'leaf', size: { x: 900, y: 1800, z: 40 }, position: { x: 0, y: 1000, z: 0 } })
|
|
146
146
|
a = addFigureBox(a, { id: 'handle', size: { x: 30, y: 150, z: 60 }, position: { x: 350, y: 1000, z: 50 } })
|
|
147
|
-
a = applyFigureAuthoring(a, { kind: 'attach', part: 'leaf',
|
|
148
|
-
a = applyFigureAuthoring(a, { kind: 'attach', part: 'handle',
|
|
147
|
+
a = applyFigureAuthoring(a, { kind: 'attach', part: 'leaf', to: { part: 'frame', face: 'top' } })
|
|
148
|
+
a = applyFigureAuthoring(a, { kind: 'attach', part: 'handle', to: { part: 'leaf', face: 'front' }, align: { x: { mm: 350 } } })
|
|
149
149
|
return serializeFigureAsset(a)
|
|
150
150
|
},
|
|
151
151
|
/* A ball: no face to lay on the floor, and not said to be tilted. */
|
|
@@ -11,7 +11,7 @@ async function start() {
|
|
|
11
11
|
asset = applyFigureAuthoring(asset, { kind: 'declare-instance-size', range: { x: { min: 50, max: 400 }, y: { min: 50, max: 400 }, z: { min: 50, max: 400 } }, at: { x: 100, y: 100, z: 100 } })
|
|
12
12
|
asset = applyFigureAuthoring(asset, { kind: 'follow-size', part: 'block', axes: ['x', 'y', 'z'] })
|
|
13
13
|
asset = applyFigureAuthoring(asset, { kind: 'set-joint', joint: {
|
|
14
|
-
id: 'block', type: 'prismatic', body0: { plane: 'mounting-plane' }, body1: { part: 'block'
|
|
14
|
+
id: 'block', type: 'prismatic', body0: { plane: 'mounting-plane' }, body1: { part: 'block' }, axis: 'X', lowerLimit: 0, upperLimit: 200, state: { id: 'shift', start: 0 }
|
|
15
15
|
} })
|
|
16
16
|
asset = editFigurePart(asset, { kind: 'set-driver', state: 'shift', clip: 'cycle', duration: 4, keys: [{ seconds: 0, value: 0 }, { seconds: 2, value: 200 }, { seconds: 4, value: 0 }] })
|
|
17
17
|
/* Its room declared from its parts over the whole motion, as the modeller does before a release. */
|
|
@@ -13,7 +13,7 @@ for (let i = 0; i < PARTS; i++) {
|
|
|
13
13
|
const id = `slide-${i}`
|
|
14
14
|
asset = addFigureBox(asset, { id, size: { x: 40, y: 40, z: 40 }, position: { x: i * 60, y: 20, z: 0 } })
|
|
15
15
|
asset = applyFigureAuthoring(asset, { kind: 'set-joint', joint: {
|
|
16
|
-
id, type: 'prismatic', body0: { plane: 'mounting-plane' }, body1: { part: id
|
|
16
|
+
id, type: 'prismatic', body0: { plane: 'mounting-plane' }, body1: { part: id }, axis: 'Z', lowerLimit: 0, upperLimit: 100, state: { id: `${id}-z`, start: 0 }
|
|
17
17
|
} })
|
|
18
18
|
asset = editFigurePart(asset, { kind: 'set-driver', state: `${id}-z`, clip: `cycle-${i}`, duration: 2, keys: [{ seconds: 0, value: 0 }, { seconds: 1, value: 100 }, { seconds: 2, value: 0 }] })
|
|
19
19
|
}
|
|
@@ -50,7 +50,7 @@ window.figures = {
|
|
|
50
50
|
a = addFigureBox(a, { id: 'frame', size: { x: 2000, y: 100, z: 200 }, position: { x: 0, y: 50, z: 0 } })
|
|
51
51
|
for (const [id, x] of [['left', -500], ['right', 500]]) {
|
|
52
52
|
a = addFigureBox(a, { id, size: { x: 900, y: 1800, z: 40 }, position: { x, y: 1000, z: 0 } })
|
|
53
|
-
a = applyFigureAuthoring(a, { kind: 'attach', part: id,
|
|
53
|
+
a = applyFigureAuthoring(a, { kind: 'attach', part: id, to: { part: 'frame', face: 'top' } })
|
|
54
54
|
const j = a.joints.find(k => k.body1.part === id)
|
|
55
55
|
a = applyFigureAuthoring(a, { kind: 'set-joint', joint: { ...j, type: 'revolute', axis: 'Y', state: { id: `${id}-open` } } })
|
|
56
56
|
a = editFigurePart(a, { kind: 'set-driver', state: `${id}-open`, clip: `${id}-swing`, duration: 2, keys: [{ seconds: 0, value: 0 }, { seconds: 2, value: 80 }] })
|
|
@@ -66,13 +66,13 @@ const words = () => read(() => [...(findDeep('div[overhang]')?.querySelectorAll(
|
|
|
66
66
|
/* A 400 × 1000 deck; a 100 mm block on it, fastened 1000 mm off its centre along X -- past its low edge. */
|
|
67
67
|
function figure(withChild = false) {
|
|
68
68
|
let a = addFigureBox(createFigureAsset('Deck'), { id: 'deck', size: { x: 400, y: 50, z: 1000 }, position: { x: 0, y: 25, z: 0 } })
|
|
69
|
-
a = applyFigureAuthoring(a, { kind: 'attach', part: 'deck',
|
|
69
|
+
a = applyFigureAuthoring(a, { kind: 'attach', part: 'deck', to: { plane: 'mounting-plane' } })
|
|
70
70
|
a = addFigureBox(a, { id: 'block', size: { x: 100, y: 100, z: 100 }, position: { x: 0, y: 100, z: 0 } })
|
|
71
|
-
a = applyFigureAuthoring(a, { kind: 'attach', part: 'block',
|
|
71
|
+
a = applyFigureAuthoring(a, { kind: 'attach', part: 'block', to: { part: 'deck', face: 'top' }, ...(withChild ? {} : { align: { x: { mm: -1000 } } }) })
|
|
72
72
|
if (!withChild) return a
|
|
73
73
|
/* The block inside; a cap on it, past the block's edge. */
|
|
74
74
|
a = addFigureBox(a, { id: 'cap', size: { x: 40, y: 40, z: 40 }, position: { x: 0, y: 170, z: 0 } })
|
|
75
|
-
return applyFigureAuthoring(a, { kind: 'attach', part: 'cap',
|
|
75
|
+
return applyFigureAuthoring(a, { kind: 'attach', part: 'cap', to: { part: 'block', face: 'top' }, align: { x: { mm: 300 } } })
|
|
76
76
|
}
|
|
77
77
|
|
|
78
78
|
describe('정렬·간격 고치기 moves a part inside the face it is fastened on', () => {
|
|
@@ -179,7 +179,7 @@ async function type(field, text) {
|
|
|
179
179
|
}
|
|
180
180
|
|
|
181
181
|
const box = (asset, id, [x, y, z], at = [0, 0, 0]) => addFigureBox(asset, { id, size: { x, y, z }, position: { x: at[0], y: at[1], z: at[2] } })
|
|
182
|
-
const fasten = (asset, part, to, more = {}) => applyFigureAuthoring(asset, { kind: 'attach', part,
|
|
182
|
+
const fasten = (asset, part, to, more = {}) => applyFigureAuthoring(asset, { kind: 'attach', part, to: to === 'plane' ? { plane: 'mounting-plane' } : { part: to, face: 'top' }, ...more })
|
|
183
183
|
const SIZE = { x: { min: 100, max: 4000 }, y: { min: 100, max: 4000 }, z: { min: 100, max: 4000 } }
|
|
184
184
|
|
|
185
185
|
describe('a size rule that would follow itself, and a fastening that would hang from itself, are refused and said', () => {
|
|
@@ -202,7 +202,7 @@ describe('a size rule that would follow itself, and a fastening that would hang
|
|
|
202
202
|
test('a fastened to b, which hangs from it: refused, said as a loop, nothing written', async () => {
|
|
203
203
|
await pick('a')
|
|
204
204
|
const start = await state()
|
|
205
|
-
await read(() => look.tell('shape', 'command', { action: { kind: 'attach', part: 'a',
|
|
205
|
+
await read(() => look.tell('shape', 'command', { action: { kind: 'attach', part: 'a', to: { part: 'b', face: 'top' } } }))
|
|
206
206
|
await until(() => probe.state().error === 'figure.text.fasten-would-loop', [], 'the loop said')
|
|
207
207
|
assert.equal((await state()).revision, start.revision, 'nothing written')
|
|
208
208
|
})
|
|
@@ -419,7 +419,7 @@ describe('a new fastening for a door leaf: chosen in the window, seen before it
|
|
|
419
419
|
})
|
|
420
420
|
|
|
421
421
|
test('a refused command clears what was drawn and says why, in the window', async () => {
|
|
422
|
-
await read(() => look.tell('dialog', 'preview-command', { action: { kind: 'attach', part: 'leaf',
|
|
422
|
+
await read(() => look.tell('dialog', 'preview-command', { action: { kind: 'attach', part: 'leaf', to: { part: 'frame', face: 'nowhere' } } }))
|
|
423
423
|
await until(() => look.all('[preview-words]', 'figure.text.preview-refused').length > 0, [], 'the refusal said')
|
|
424
424
|
assert.deepEqual(await ghosts(), [], 'nothing of the earlier result drawn')
|
|
425
425
|
})
|
|
@@ -490,15 +490,26 @@ async function pressFixAlignment() {
|
|
|
490
490
|
describe('past the edge of the face a part is fastened to', () => {
|
|
491
491
|
before(async () => {
|
|
492
492
|
let a = fasten(box(createFigureAsset('Overhangs'), 'frame', [1000, 100, 400], [0, 50, 0]), 'frame', 'plane')
|
|
493
|
-
/* Pushed 30 mm past the frame's right edge;
|
|
493
|
+
/* Pushed 30 mm past the frame's right edge; a mesh turned on it, its box past the edge; on a drum's round end; wider than the frame, off to one side. */
|
|
494
494
|
a = fasten(box(a, 'out', [100, 100, 100]), 'out', 'frame', { align: { x: { mm: 480 } } })
|
|
495
|
-
|
|
495
|
+
const mesh = { asset: 'a'.repeat(64), format: 'glb', unit: 'mm', bounds: { min: { x: -50, y: -50, z: -50 }, max: { x: 50, y: 50, z: 50 } }, triangles: 12, primitives: 1 }
|
|
496
|
+
a = addFigurePrimitive(a, { id: 'tilted', kind: 'mesh', dimensions: { size: 100 }, mesh, position: { x: 0, y: 0, z: 0 } })
|
|
497
|
+
a = applyFigureAuthoring(a, { kind: 'set-joint', joint: { id: 'tilted', type: 'fixed', body0: { part: 'frame', face: 'top' }, body1: { part: 'tilted' }, origin: { align: { x: { mm: 460 } }, childRotate: { y: 30 } } } })
|
|
496
498
|
a = fasten(addFigurePrimitive(a, { id: 'drum', kind: 'cylinder', dimensions: { radius: 100, length: 200 }, position: { x: 0, y: 0, z: 0 } }), 'drum', 'frame')
|
|
497
499
|
a = fasten(box(a, 'cap', [50, 50, 50]), 'cap', 'drum')
|
|
498
500
|
await mount('overhangs', fasten(box(a, 'plate', [1600, 20, 200]), 'plate', 'frame', { align: { x: { mm: 200 } } }))
|
|
499
501
|
})
|
|
500
502
|
const overhang = () => read(() => look.all('div[overhang] p').map(p => p.text))
|
|
501
503
|
|
|
504
|
+
test('the face a part is held on is lit while the panel names it, whichever part is chosen (UX lane, ADR-0140 3.11)', async () => {
|
|
505
|
+
const litAt = y => Math.abs((document.querySelector('figure-editor').shadowRoot.querySelector('figure-canvas').highlight?.pose.t[1] ?? 0) - y) < 2
|
|
506
|
+
await pick('out')
|
|
507
|
+
await until(() => look.all('div[fastened] p', 'figure.text.held-on-part').length + look.all('p[fasten-sentence]').length > 0, [], 'the panel names where it is held')
|
|
508
|
+
await until(litAt, [102], "the frame's top lit (the lit plate a little over it)")
|
|
509
|
+
await pick('cap')
|
|
510
|
+
await until(litAt, [302], "the drum's top lit")
|
|
511
|
+
})
|
|
512
|
+
|
|
502
513
|
test('past it: said, and "fix alignment" moves it inside the face as one step', async () => {
|
|
503
514
|
await pick('out')
|
|
504
515
|
await until(() => look.all('div[overhang] p', 'figure.text.overhang-out').length === 1, [], 'said past the edge')
|
|
@@ -508,7 +519,7 @@ describe('past the edge of the face a part is fastened to', () => {
|
|
|
508
519
|
await until(() => look.all('div[overhang] p', 'figure.text.overhang-out').length === 0, [], 'no longer past the edge')
|
|
509
520
|
})
|
|
510
521
|
|
|
511
|
-
test('turned, it may be past it: said so', async () => {
|
|
522
|
+
test('a mesh turned on the face, its box past it, may be past it: said so', async () => {
|
|
512
523
|
await pick('tilted')
|
|
513
524
|
await until(() => look.all('div[overhang] p', 'figure.text.overhang-possible').length === 1, [], 'said it may be')
|
|
514
525
|
})
|
|
@@ -596,10 +607,11 @@ describe('a bench: what each part is fastened to, what detaching would do, a row
|
|
|
596
607
|
})
|
|
597
608
|
})
|
|
598
609
|
|
|
599
|
-
/* A blade fastened
|
|
610
|
+
/* A blade fastened tilted on a hub (off a quarter turn): no side of its own figure-model can keep for a size drag. */
|
|
600
611
|
function twisted() {
|
|
601
612
|
const a = fasten(box(createFigureAsset('Fan'), 'hub', [200, 100, 200], [0, 50, 0]), 'hub', 'plane')
|
|
602
|
-
|
|
613
|
+
const on = fasten(box(a, 'blade', [300, 20, 60], [0, 110, 0]), 'blade', 'hub')
|
|
614
|
+
return applyFigureAuthoring(on, { kind: 'set-joint', joint: { ...on.joints.find(j => j.id === 'blade'), origin: { childRotate: { z: 30 } } } })
|
|
603
615
|
}
|
|
604
616
|
|
|
605
617
|
/* The same blade, every side of it following the hub's (as the fan's blade-2 on :3300): no size of its own to type. */
|
|
@@ -67,11 +67,11 @@ function sourceOf(kind, text) {
|
|
|
67
67
|
let asset = createFigureAsset('Rollers')
|
|
68
68
|
asset.palette = { ...asset.palette, ...PALETTE }
|
|
69
69
|
asset = addFigureBox(asset, { id: 'bed', size: { x: 2000, y: 400, z: 600 }, position: { x: 0, y: 200, z: 0 } })
|
|
70
|
-
asset = applyFigureAuthoring(asset, { kind: 'attach', part: 'bed',
|
|
70
|
+
asset = applyFigureAuthoring(asset, { kind: 'attach', part: 'bed', to: { plane: 'mounting-plane' } })
|
|
71
71
|
asset = addFigurePrimitive(asset, { id: 'roller', kind: 'cylinder', dimensions: { radius: 40, length: 560 }, position: { x: 0, y: 0, z: 0 }, rotation: { x: 90, y: 0, z: 0 } })
|
|
72
|
-
asset = applyFigureAuthoring(asset, { kind: 'attach', part: 'roller',
|
|
72
|
+
asset = applyFigureAuthoring(asset, { kind: 'attach', part: 'roller', facing: 'centre', to: { part: 'bed', face: 'top' }, gap: 40 })
|
|
73
73
|
asset = addFigureBox(asset, { id: 'mark', size: { x: 30, y: 30, z: 560 }, position: { x: 0, y: 0, z: 0 } })
|
|
74
|
-
asset = applyFigureAuthoring(asset, { kind: 'attach', part: 'mark',
|
|
74
|
+
asset = applyFigureAuthoring(asset, { kind: 'attach', part: 'mark', to: { part: 'roller', face: 'right' } })
|
|
75
75
|
const j = asset.joints.find(o => o.body1.part === 'roller')
|
|
76
76
|
asset = applyFigureAuthoring(asset, { kind: 'set-joint', joint: { ...j, type: 'revolute', axis: 'Z', lowerLimit: -360, upperLimit: 360, state: { id: 'spin' } } })
|
|
77
77
|
return serializeFigureAsset(applyFigureAuthoring(asset, { kind: 'make-repeat', part: 'roller', axis: 'x', pitch: 200 }))
|
|
@@ -50,9 +50,9 @@ async function click(selector, options = {}, what = selector) {
|
|
|
50
50
|
/* box-1 on the floor, box-2 on it made into a row 300 apart: box-2's id is drawn nowhere as it is. */
|
|
51
51
|
function rowed() {
|
|
52
52
|
let a = addFigureBox(createFigureAsset('Rowed'), { id: 'box-1', size: { x: 1000, y: 100, z: 400 }, position: { x: 0, y: 50, z: 0 } })
|
|
53
|
-
a = applyFigureAuthoring(a, { kind: 'attach', part: 'box-1',
|
|
53
|
+
a = applyFigureAuthoring(a, { kind: 'attach', part: 'box-1', to: { plane: 'mounting-plane' } })
|
|
54
54
|
a = addFigureBox(a, { id: 'box-2', size: { x: 100, y: 100, z: 100 }, position: { x: 0, y: 150, z: 0 } })
|
|
55
|
-
a = applyFigureAuthoring(a, { kind: 'attach', part: 'box-2',
|
|
55
|
+
a = applyFigureAuthoring(a, { kind: 'attach', part: 'box-2', to: { part: 'box-1', face: 'top' } })
|
|
56
56
|
a = applyFigureAuthoring(a, { kind: 'make-repeat', part: 'box-2', axis: 'x', pitch: 300 })
|
|
57
57
|
/* A part off to one side, free: its mirrored copy lands on the other side. */
|
|
58
58
|
return addFigureBox(a, { id: 'side', size: { x: 100, y: 100, z: 100 }, position: { x: 900, y: 50, z: 0 } })
|
|
@@ -33,7 +33,7 @@ Object.assign(window.figures, {
|
|
|
33
33
|
let a = figure('Fastened')
|
|
34
34
|
a = addFigureBox(a, { id: 'frame', size: { x: 1600, y: 100, z: 150 }, position: { x: 0, y: 50, z: 0 } })
|
|
35
35
|
a = addFigureBox(a, { id: 'leaf', size: { x: 1400, y: 1000, z: 40 }, position: { x: 0, y: 600, z: 0 } })
|
|
36
|
-
return serializeFigureAsset(applyFigureAuthoring(a, { kind: 'attach', part: 'leaf',
|
|
36
|
+
return serializeFigureAsset(applyFigureAuthoring(a, { kind: 'attach', part: 'leaf', to: { part: 'frame', face: 'top' } }))
|
|
37
37
|
},
|
|
38
38
|
/* A box with rounded corners: made from the box, still called what it is. */
|
|
39
39
|
/* A housing and a stray part on the floor, the space the figure takes declared from both. */
|
|
@@ -41,7 +41,7 @@ Object.assign(window.figures, {
|
|
|
41
41
|
let a = figure('Gate')
|
|
42
42
|
a = addFigureBox(a, { id: 'housing', size: { x: 300, y: 1000, z: 300 }, position: { x: 0, y: 500, z: 0 } })
|
|
43
43
|
a = addFigureBox(a, { id: 'stray', size: { x: 100, y: 100, z: 100 }, position: { x: 600, y: 50, z: 0 } })
|
|
44
|
-
for (const part of ['housing', 'stray']) a = applyFigureAuthoring(a, { kind: 'attach', part,
|
|
44
|
+
for (const part of ['housing', 'stray']) a = applyFigureAuthoring(a, { kind: 'attach', part, to: { plane: 'mounting-plane' } })
|
|
45
45
|
return serializeFigureAsset(applyFigureAuthoring(a, { kind: 'declare-occupancy', proposal: proposeFigureOccupancy(a), placement: 'floor' }))
|
|
46
46
|
},
|
|
47
47
|
rounded: () => {
|
|
@@ -611,10 +611,10 @@ describe('the page around the figure: the shell, the dock, the properties', () =
|
|
|
611
611
|
})
|
|
612
612
|
|
|
613
613
|
describe('a placement the figure\'s parts refuse, chosen on the properties tab (wall placement, 09-25)', () => {
|
|
614
|
-
/* A post standing on the floor's plane
|
|
614
|
+
/* A post standing on the floor's plane: a wall's plane faces another way, so the post is named and the wall refused. */
|
|
615
615
|
const post = () => {
|
|
616
616
|
const a = addFigureBox(createFigureAsset('Post'), { id: 'post', size: { x: 100, y: 1000, z: 100 }, position: { x: 0, y: 500, z: 0 } })
|
|
617
|
-
return serializeFigureAsset(applyFigureAuthoring(a, { kind: 'attach', part: 'post',
|
|
617
|
+
return serializeFigureAsset(applyFigureAuthoring(a, { kind: 'attach', part: 'post', to: { plane: 'mounting-plane' } }))
|
|
618
618
|
}
|
|
619
619
|
const placement = () =>
|
|
620
620
|
read(() => {
|
|
@@ -640,7 +640,7 @@ describe('a placement the figure\'s parts refuse, chosen on the properties tab (
|
|
|
640
640
|
const said = await until(() => product.deep('figure-modeller-page >>> p[fit-error]')[0]?.textContent.trim(), 'the refusal said')
|
|
641
641
|
/* Said from the kernel's details (ADR-0127): the page loads no translations, so the words are the key with its values. */
|
|
642
642
|
assert.match(said, /^figure\.text\./, said)
|
|
643
|
-
assert.ok(said.includes('post')
|
|
643
|
+
assert.ok(said.includes('post'), `names the part to fasten again: ${said}`)
|
|
644
644
|
assert.equal(await revision(), start, 'nothing written')
|
|
645
645
|
assert.equal(await placement(), 'floor', 'the list says the placement the figure has')
|
|
646
646
|
})
|
|
@@ -45,7 +45,7 @@ export function doorSource() {
|
|
|
45
45
|
a.palette = { ...a.palette, ...PALETTE }
|
|
46
46
|
a = addFigureBox(a, { id: 'frame', size: { x: 1000, y: 100, z: 200 }, position: { x: 0, y: 50, z: 0 } })
|
|
47
47
|
a = addFigureBox(a, { id: 'leaf', size: { x: 900, y: 1800, z: 40 }, position: { x: 0, y: 1000, z: 0 } })
|
|
48
|
-
a = applyFigureAuthoring(a, { kind: 'attach', part: 'leaf',
|
|
48
|
+
a = applyFigureAuthoring(a, { kind: 'attach', part: 'leaf', to: { part: 'frame', face: 'top' } })
|
|
49
49
|
const j = a.joints.find(k => k.body1.part === 'leaf')
|
|
50
50
|
a = applyFigureAuthoring(a, { kind: 'set-joint', joint: { ...j, type: 'revolute', axis: 'Y', state: { id: 'open' } } })
|
|
51
51
|
a = editFigurePart(a, { kind: 'set-driver', state: 'open', clip: 'swing', duration: 2, keys: [{ seconds: 0, value: 0 }, { seconds: 2, value: 80 }] })
|
|
@@ -48,9 +48,9 @@ const said = () => read(() => [...(findDeep('section[row]')?.querySelectorAll('[
|
|
|
48
48
|
/* A 400 mm board, a 3 mm bin fastened on it: a row of it along X. */
|
|
49
49
|
function board() {
|
|
50
50
|
let a = addFigureBox(createFigureAsset('Board'), { id: 'board', size: { x: 400, y: 50, z: 1000 }, position: { x: 0, y: 25, z: 0 } })
|
|
51
|
-
a = applyFigureAuthoring(a, { kind: 'attach', part: 'board',
|
|
51
|
+
a = applyFigureAuthoring(a, { kind: 'attach', part: 'board', to: { plane: 'mounting-plane' } })
|
|
52
52
|
a = addFigureBox(a, { id: 'bin', size: { x: 3, y: 100, z: 100 }, position: { x: 0, y: 100, z: 0 } })
|
|
53
|
-
return applyFigureAuthoring(a, { kind: 'attach', part: 'bin',
|
|
53
|
+
return applyFigureAuthoring(a, { kind: 'attach', part: 'bin', to: { part: 'board', face: 'top' } })
|
|
54
54
|
}
|
|
55
55
|
|
|
56
56
|
describe('a row\'s preview follows its basis', () => {
|
|
@@ -57,7 +57,7 @@ const FIGURES = {
|
|
|
57
57
|
/* A lighting tower that follows its height only: the wider variants ask a width it does not declare. */
|
|
58
58
|
tower: () => {
|
|
59
59
|
let a = addFigureBox(named('Tower'), { id: 'mast', size: { x: 200, y: 2000, z: 300 }, position: { x: 0, y: 0, z: 0 } })
|
|
60
|
-
a = applyFigureAuthoring(a, { kind: 'attach', part: 'mast',
|
|
60
|
+
a = applyFigureAuthoring(a, { kind: 'attach', part: 'mast', to: { plane: 'mounting-plane' } })
|
|
61
61
|
return applyFigureAuthoring(a, { kind: 'declare-instance-size', range: { x: { min: 200, max: 200 }, y: { min: 1000, max: 3000 }, z: { min: 300, max: 300 } } })
|
|
62
62
|
},
|
|
63
63
|
/*
|
|
@@ -67,7 +67,7 @@ const FIGURES = {
|
|
|
67
67
|
stack: () => {
|
|
68
68
|
let a = addFigureBox(named('Stack'), { id: 'base', size: { x: 1000, y: 200, z: 600 }, position: { x: 0, y: 100, z: 0 } })
|
|
69
69
|
a = addFigureBox(a, { id: 'top', size: { x: 200, y: 200, z: 200 }, position: { x: 0, y: 300, z: 0 } })
|
|
70
|
-
a = applyFigureAuthoring(a, { kind: 'attach', part: 'top',
|
|
70
|
+
a = applyFigureAuthoring(a, { kind: 'attach', part: 'top', to: { part: 'base', face: 'top' } })
|
|
71
71
|
a = applyFigureAuthoring(a, { kind: 'declare-occupancy', proposal: proposeFigureOccupancy(a) })
|
|
72
72
|
return applyFigureAuthoring(a, { kind: 'set-mounting-face', part: 'base', face: 'bottom' })
|
|
73
73
|
},
|
|
@@ -75,7 +75,7 @@ const FIGURES = {
|
|
|
75
75
|
stretch: () => {
|
|
76
76
|
let a = addFigureBox(named('Stretch'), { id: 'frame', size: { x: 2000, y: 100, z: 600 }, position: { x: 0, y: 50, z: 0 } })
|
|
77
77
|
a = addFigurePrimitive(a, { id: 'roller', kind: 'cylinder', dimensions: { radius: 30, length: 560 }, position: { x: 0, y: 0, z: 0 }, rotation: { x: 90, y: 0, z: 0 } })
|
|
78
|
-
a = applyFigureAuthoring(a, { kind: 'attach', part: 'roller',
|
|
78
|
+
a = applyFigureAuthoring(a, { kind: 'attach', part: 'roller', to: { part: 'frame', face: 'top' } })
|
|
79
79
|
a = applyFigureAuthoring(a, { kind: 'follow-size', part: 'frame', axes: ['x'] })
|
|
80
80
|
a = applyFigureAuthoring(a, { kind: 'make-repeat', part: 'roller', axis: 'x', pitch: 200 })
|
|
81
81
|
/* A space wider than the parts, as a spin swept or a padding gives: the box is the space, not the size (2026-10-16). */
|
|
@@ -27,7 +27,7 @@ const FIGURES = {
|
|
|
27
27
|
/* The triangle with a plate on its top: its end cannot be drawn to one point while the plate stands there (A5-1). */
|
|
28
28
|
'capped-wedge': () => {
|
|
29
29
|
const a = addFigureBox(polygon(figure('Capped'), 'wedge', TRIANGLE), { id: 'cap', size: { x: 100, y: 20, z: 100 }, position: { x: 0, y: 0, z: 0 } })
|
|
30
|
-
return applyFigureAuthoring(a, { kind: 'attach', part: 'cap',
|
|
30
|
+
return applyFigureAuthoring(a, { kind: 'attach', part: 'cap', to: { part: 'wedge', face: 'top' } })
|
|
31
31
|
},
|
|
32
32
|
pyramid: () => applyFigureAuthoring(polygon(figure('Pyramid'), 'wedge', TRIANGLE), { kind: 'set-section', part: 'wedge', apex: { x: 0, z: 0 } }),
|
|
33
33
|
/* A box standing on the floor: a length change keeps its bottom. */
|
|
@@ -51,10 +51,10 @@ const FIGURES = {
|
|
|
51
51
|
/* A tote on the floor with a divider standing on its inside floor, and a box beside it (ADR-0100 A8). */
|
|
52
52
|
tote: () => {
|
|
53
53
|
let a = addFigureBox(figure('Tote'), { id: 'bin', size: { x: 600, y: 300, z: 400 }, position: { x: 0, y: 150, z: 0 } })
|
|
54
|
-
a = applyFigureAuthoring(a, { kind: 'attach', part: 'bin',
|
|
54
|
+
a = applyFigureAuthoring(a, { kind: 'attach', part: 'bin', to: { plane: 'mounting-plane' } })
|
|
55
55
|
a = applyFigureAuthoring(a, { kind: 'set-cavity', part: 'bin', cavity: { wall: 10, start: { closed: 15 }, end: 'open' } })
|
|
56
56
|
a = addFigureBox(a, { id: 'divider', size: { x: 10, y: 200, z: 380 }, position: { x: 0, y: 0, z: 0 } })
|
|
57
|
-
return beside(applyFigureAuthoring(a, { kind: 'attach', part: 'divider',
|
|
57
|
+
return beside(applyFigureAuthoring(a, { kind: 'attach', part: 'divider', to: { part: 'bin', face: 'inside-bottom' } }))
|
|
58
58
|
}
|
|
59
59
|
}
|
|
60
60
|
|
|
@@ -574,7 +574,7 @@ describe('the fastening drawing in the fastening window', () => {
|
|
|
574
574
|
assert.deepEqual([now.body0.face, now.origin?.facing], [face, 'flush'])
|
|
575
575
|
})
|
|
576
576
|
|
|
577
|
-
test('fastened to the plane: the plane is named by the placement, chosen, and set on
|
|
577
|
+
test('fastened to the plane: the plane is named by the placement, chosen, and set on it or hung below it', async () => {
|
|
578
578
|
await mount('rollers')
|
|
579
579
|
await pick('bed')
|
|
580
580
|
await change()
|
|
@@ -582,7 +582,7 @@ describe('the fastening drawing in the fastening window', () => {
|
|
|
582
582
|
const plane = list.find(t => t.target === '__plane')
|
|
583
583
|
assert.deepEqual([plane.selected, plane.text], [true, 'figure.label.resize-place-floor'])
|
|
584
584
|
assert.equal((await labels())[1], 'figure.label.fasten-face-on-plane', 'the face asked on the floor, not of a part')
|
|
585
|
-
assert.deepEqual((await read(() => probe.fastenDrawing())).modes, [], '
|
|
585
|
+
assert.deepEqual((await read(() => probe.fastenDrawing())).modes, ['meet', 'flush'], 'the floor: stood on, or hung below (ADR-0140 3.11)')
|
|
586
586
|
})
|
|
587
587
|
|
|
588
588
|
/* The window is a popup over the work: closed, nothing written, before another part is picked. */
|
|
@@ -602,7 +602,7 @@ describe('the fastening drawing in the fastening window', () => {
|
|
|
602
602
|
assert.deepEqual((await read(() => probe.fastenDrawing())).modes, ['meet', 'flush'])
|
|
603
603
|
})
|
|
604
604
|
|
|
605
|
-
test('a new fastening waits for 붙이기; the part
|
|
605
|
+
test('a new fastening waits for 붙이기; the part meets the target\'s face, by no face of its own', async () => {
|
|
606
606
|
await mount('door')
|
|
607
607
|
await pick('leaf')
|
|
608
608
|
await press('button[fasten-start]')
|
|
@@ -617,7 +617,7 @@ describe('the fastening drawing in the fastening window', () => {
|
|
|
617
617
|
await until(r => probe.state().revision === r + 1, 'one step', start.revision)
|
|
618
618
|
const joint = await read(() => probe.fastening('leaf'))
|
|
619
619
|
assert.deepEqual(joint.body0, { part: 'frame', face: 'front' })
|
|
620
|
-
assert.
|
|
620
|
+
assert.deepEqual([joint.body1, joint.origin?.facing], [{ part: 'leaf' }, 'meet'], 'set on the front by its real shape (ADR-0140 3.2)')
|
|
621
621
|
})
|
|
622
622
|
})
|
|
623
623
|
|
|
@@ -21,7 +21,7 @@ function door(): string {
|
|
|
21
21
|
a = addFigureBox(a, { id: 'frame', size: { x: 1000, y: 100, z: 200 }, position: { x: 0, y: 50, z: 0 } })
|
|
22
22
|
a = addFigureBox(a, { id: 'leaf', size: { x: 900, y: 1800, z: 40 }, position: { x: 0, y: 1000, z: 0 } })
|
|
23
23
|
a = addFigureBox(a, { id: 'sign', size: { x: 200, y: 100, z: 10 }, position: { x: 0, y: 2200, z: 200 } })
|
|
24
|
-
a = applyFigureAuthoring(a, { kind: 'attach', part: 'leaf',
|
|
24
|
+
a = applyFigureAuthoring(a, { kind: 'attach', part: 'leaf', to: { part: 'frame', face: 'top' } })
|
|
25
25
|
const j = a.joints!.find(k => k.body1.part === 'leaf')!
|
|
26
26
|
a = applyFigureAuthoring(a, { kind: 'set-joint', joint: { ...j, type: 'revolute', axis: 'Y', state: { id: 'open' } } })
|
|
27
27
|
a = editFigurePart(a, { kind: 'set-driver', state: 'open', clip: 'swing', duration: 2, keys: [{ seconds: 0, value: 0 }, { seconds: 2, value: 80 }] })
|
|
@@ -20,7 +20,7 @@ function doors(): string {
|
|
|
20
20
|
a = addFigureBox(a, { id: 'frame', size: { x: 2000, y: 100, z: 200 }, position: { x: 0, y: 50, z: 0 } })
|
|
21
21
|
for (const [id, x] of [['left', -500], ['right', 500]] as const) {
|
|
22
22
|
a = addFigureBox(a, { id, size: { x: 900, y: 1800, z: 40 }, position: { x, y: 1000, z: 0 } })
|
|
23
|
-
a = applyFigureAuthoring(a, { kind: 'attach', part: id,
|
|
23
|
+
a = applyFigureAuthoring(a, { kind: 'attach', part: id, to: { part: 'frame', face: 'top' } })
|
|
24
24
|
const j = a.joints!.find(k => k.body1.part === id)!
|
|
25
25
|
a = applyFigureAuthoring(a, { kind: 'set-joint', joint: { ...j, type: 'revolute', axis: 'Y', state: { id: `${id}-open` } } })
|
|
26
26
|
a = editFigurePart(a, { kind: 'set-driver', state: `${id}-open`, clip: `${id}-swing`, duration: 2, keys: [{ seconds: 0, value: 0 }, { seconds: 2, value: 80 }] })
|
|
@@ -26,11 +26,11 @@ function bench(): string {
|
|
|
26
26
|
a = addFigureBox(a, { id: 'leg', size: { x: 60, y: 700, z: 60 }, position: { x: -400, y: 350, z: 0 } })
|
|
27
27
|
a = addFigureBox(a, { id: 'top', size: { x: 1200, y: 40, z: 600 }, position: { x: 0, y: 900, z: 0 } })
|
|
28
28
|
a = addFigureBox(a, { id: 'lamp', size: { x: 80, y: 80, z: 80 }, position: { x: 200, y: 960, z: 100 } })
|
|
29
|
-
a = applyFigureAuthoring(a, { kind: 'attach', part: 'lamp',
|
|
29
|
+
a = applyFigureAuthoring(a, { kind: 'attach', part: 'lamp', to: { part: 'top', face: 'top' } })
|
|
30
30
|
return serializeFigureAsset(a)
|
|
31
31
|
}
|
|
32
32
|
const store = { load: async (id: string) => ({ id, source: bench() }), save: async (q: { id?: string; source: string }) => ({ id: q.id ?? 'x', source: q.source }) }
|
|
33
|
-
const onLeg = { kind: 'attach', part: 'top',
|
|
33
|
+
const onLeg = { kind: 'attach', part: 'top', to: { part: 'leg', face: 'top' } } as never
|
|
34
34
|
|
|
35
35
|
test('seen, not done: the session\'s preview writes nothing, and names the version it was worked out on', async () => {
|
|
36
36
|
const s = createFigureProductSession(store)
|
|
@@ -78,7 +78,7 @@ test('the face it would meet is lit where attaching reads it, just off the face'
|
|
|
78
78
|
test('the details fold, and what they hold that is not the default stays said -- nothing for the default', () => {
|
|
79
79
|
for (const lang of ['en', 'ja', 'ko', 'ms', 'zh', 'es']) {
|
|
80
80
|
const t = JSON.parse(read(`../translations/${lang}.json`))
|
|
81
|
-
for (const key of ['preview-refused', 'preview-stays', 'preview-moves', 'preview-turns-named', 'preview-turns-slanted', 'preview-carries', 'preview-copies', 'preview-clips', 'preview-face-unknown', 'target-would-loop', 'fasten-summary-gap'
|
|
81
|
+
for (const key of ['preview-refused', 'preview-stays', 'preview-moves', 'preview-turns-named', 'preview-turns-slanted', 'preview-carries', 'preview-copies', 'preview-clips', 'preview-face-unknown', 'target-would-loop', 'fasten-summary-gap'])
|
|
82
82
|
assert.ok(t[`figure.text.${key}`], `${lang} ${key}`)
|
|
83
83
|
assert.ok(t['figure.label.fasten-detail'] && t['figure.label.facing'], lang)
|
|
84
84
|
}
|
|
@@ -106,7 +106,7 @@ test('a row is seen before it is made, read as figure-model draws it -- and said
|
|
|
106
106
|
a = addFigureBox(a, { id: 'frame', size: { x: 2000, y: 100, z: 600 }, position: { x: 0, y: 50, z: 0 } })
|
|
107
107
|
a = addFigureBox(a, { id: 'roller', size: { x: 60, y: 60, z: 560 }, position: { x: 0, y: 130, z: 0 } })
|
|
108
108
|
assert.equal(rowBlockOf(a, 'roller'), 'unfastened')
|
|
109
|
-
a = applyFigureAuthoring(a, { kind: 'attach', part: 'roller',
|
|
109
|
+
a = applyFigureAuthoring(a, { kind: 'attach', part: 'roller', to: { part: 'frame', face: 'top' } })
|
|
110
110
|
assert.equal(rowBlockOf(a, 'roller'), undefined)
|
|
111
111
|
const seen = previewFigureCommand(a, { kind: 'make-repeat', part: 'roller', axis: 'x', pitch: 200 } as never)
|
|
112
112
|
const held: HeldPreview = { context: 'c', revision: 0, key: 'k', geometry: seen.geometry, moves: seen.moves, added: seen.added, row: figureRowOf(seen.asset, 'roller') }
|
|
@@ -127,7 +127,7 @@ test('a published pitch typed into its field is one edit, undone once', async ()
|
|
|
127
127
|
let a = createFigureAsset('Conveyor')
|
|
128
128
|
a = addFigureBox(a, { id: 'frame', size: { x: 2000, y: 100, z: 600 }, position: { x: 0, y: 50, z: 0 } })
|
|
129
129
|
a = addFigureBox(a, { id: 'roller', size: { x: 60, y: 60, z: 560 }, position: { x: 0, y: 130, z: 0 } })
|
|
130
|
-
a = applyFigureAuthoring(a, { kind: 'attach', part: 'roller',
|
|
130
|
+
a = applyFigureAuthoring(a, { kind: 'attach', part: 'roller', to: { part: 'frame', face: 'top' } })
|
|
131
131
|
a = applyFigureAuthoring(a, { kind: 'make-repeat', part: 'roller', axis: 'x', pitch: 200 })
|
|
132
132
|
const source = serializeFigureAsset(a)
|
|
133
133
|
const s = createFigureProductSession({ load: async (id: string) => ({ id, source }), save: async (q: { id?: string; source: string }) => ({ id: q.id ?? 'x', source: q.source }) })
|
|
@@ -157,8 +157,8 @@ test('a motion is named by its parts, and drawn at both ends of its range -- onl
|
|
|
157
157
|
a = addFigureBox(a, { id: 'frame', size: { x: 2000, y: 100, z: 200 }, position: { x: 0, y: 50, z: 0 } })
|
|
158
158
|
a = addFigureBox(a, { id: 'leaf', size: { x: 900, y: 1800, z: 40 }, position: { x: 0, y: 1000, z: 0 } })
|
|
159
159
|
a = addFigureBox(a, { id: 'gate', size: { x: 400, y: 400, z: 40 }, position: { x: 700, y: 300, z: 0 } })
|
|
160
|
-
a = applyFigureAuthoring(a, { kind: 'attach', part: 'leaf',
|
|
161
|
-
a = applyFigureAuthoring(a, { kind: 'attach', part: 'gate',
|
|
160
|
+
a = applyFigureAuthoring(a, { kind: 'attach', part: 'leaf', to: { part: 'frame', face: 'top' } })
|
|
161
|
+
a = applyFigureAuthoring(a, { kind: 'attach', part: 'gate', to: { part: 'frame', face: 'top' } })
|
|
162
162
|
const j = (part: string) => a.joints!.find(k => k.body1.part === part)!
|
|
163
163
|
assert.equal(motionEndsOf(revisionOf(a), 'leaf'), null, 'not moving: nothing drawn')
|
|
164
164
|
a = applyFigureAuthoring(a, { kind: 'set-joint', joint: { ...j('leaf'), type: 'revolute', axis: 'Y', lowerLimit: 0, upperLimit: 90, state: { id: 'open' } } })
|
|
@@ -190,7 +190,7 @@ test('a moving part is made into a row, and a row given or relieved of a motion
|
|
|
190
190
|
let a = createFigureAsset('Conveyor')
|
|
191
191
|
a = addFigureBox(a, { id: 'frame', size: { x: 2000, y: 100, z: 600 }, position: { x: 0, y: 50, z: 0 } })
|
|
192
192
|
a = addFigureBox(a, { id: 'roller', size: { x: 60, y: 60, z: 560 }, position: { x: 0, y: 130, z: 0 } })
|
|
193
|
-
a = applyFigureAuthoring(a, { kind: 'attach', part: 'roller',
|
|
193
|
+
a = applyFigureAuthoring(a, { kind: 'attach', part: 'roller', to: { part: 'frame', face: 'top' } })
|
|
194
194
|
const source = serializeFigureAsset(a)
|
|
195
195
|
const s = createFigureProductSession({ load: async (id: string) => ({ id, source }), save: async (q: { id?: string; source: string }) => ({ id: q.id ?? 'x', source: q.source }) })
|
|
196
196
|
await s.open('conveyor')
|
|
@@ -17,10 +17,10 @@ import { DETACH, faceMappingRowsOf, remapOf, rowKey } from '../client/modeller/f
|
|
|
17
17
|
/** A tote with a floor inside and a divider standing on it. */
|
|
18
18
|
function tote(): FigureAsset {
|
|
19
19
|
let asset = addFigureBox(createFigureAsset('Tote'), { id: 'bin', size: { x: 600, y: 300, z: 400 }, position: { x: 0, y: 150, z: 0 } })
|
|
20
|
-
asset = applyFigureAuthoring(asset, { kind: 'attach', part: 'bin',
|
|
20
|
+
asset = applyFigureAuthoring(asset, { kind: 'attach', part: 'bin', to: { plane: 'mounting-plane' } })
|
|
21
21
|
asset = applyFigureAuthoring(asset, { kind: 'set-cavity', part: 'bin', cavity: { wall: 10, start: { closed: 15 }, end: 'open' } })
|
|
22
22
|
asset = addFigureBox(asset, { id: 'divider', size: { x: 10, y: 200, z: 380 }, position: { x: 0, y: 0, z: 0 } })
|
|
23
|
-
return applyFigureAuthoring(asset, { kind: 'attach', part: 'divider',
|
|
23
|
+
return applyFigureAuthoring(asset, { kind: 'attach', part: 'divider', to: { part: 'bin', face: 'inside-bottom' as never } })
|
|
24
24
|
}
|
|
25
25
|
const open = { kind: 'set-cavity', part: 'bin', cavity: { wall: 10, start: 'open', end: 'open' } } as const
|
|
26
26
|
const needOf = (asset: FigureAsset): FigureFaceMappingNeed => {
|
|
@@ -14,9 +14,21 @@ const ko = JSON.parse(read('../translations/ko.json')) as Record<string, string>
|
|
|
14
14
|
const say = (key: string, params: Record<string, string>) => Object.entries(params).reduce((s, [k, v]) => s.replace(`{${k}}`, v), ko[key] ?? key)
|
|
15
15
|
|
|
16
16
|
test('화면 문구는 결과와 예외만 — 한 줄 요약, 가장자리 밖, 닿지 않음', () => {
|
|
17
|
-
assert.equal(say('figure.text.fasten-sentence-meet', {
|
|
18
|
-
assert.equal(say('figure.text.fasten-sentence-
|
|
17
|
+
assert.equal(say('figure.text.fasten-sentence-meet', { to: 'bin의 윗면' }), 'bin의 윗면에 올려놓기')
|
|
18
|
+
assert.equal(say('figure.text.fasten-sentence-flush', { to: 'bin의 윗면' }), 'bin의 윗면과 같은 면에 붙이기')
|
|
19
|
+
assert.equal(say('figure.text.fasten-sentence-centre', { to: 'frame의 앞면' }), 'frame의 앞면 가운데에 붙이기')
|
|
19
20
|
for (const key of ['figure.text.fasten-off-face', 'figure.text.fasten-past-edges', 'figure.label.fasten-mode-meet', 'figure.label.fasten-mode-flush', 'figure.label.fasten-mode-centre'])
|
|
20
21
|
for (const lang of ['ko', 'en', 'ja', 'zh', 'ms', 'es']) assert.ok((JSON.parse(read(`../translations/${lang}.json`)) as Record<string, string>)[key], `${lang} ${key}`)
|
|
21
22
|
assert.ok(!/끌어 옮깁니다|면 밖으로도/.test(JSON.stringify(ko)), 'no instructions on the screen')
|
|
23
|
+
/* The part meets by its real shape, by no face of its own (ADR-0140 3.2): no sentence names one, in any language (UX lane 10-19). */
|
|
24
|
+
for (const lang of ['ko', 'en', 'ja', 'zh', 'ms', 'es']) {
|
|
25
|
+
const t = JSON.parse(read(`../translations/${lang}.json`)) as Record<string, string>
|
|
26
|
+
for (const key of ['fasten-sentence-meet', 'fasten-sentence-flush', 'fasten-sentence-centre', 'held-on-part', 'held-on-plane', 'held-on-plane-worked-out'])
|
|
27
|
+
assert.ok(!t[`figure.text.${key}`]!.includes('{face}'), `${lang} ${key}`)
|
|
28
|
+
/* The part the window is open on is not named again: a name's last letter picks the particle (원기둥를, 판를). */
|
|
29
|
+
for (const key of ['fasten-sentence-meet', 'fasten-sentence-flush', 'fasten-sentence-centre']) assert.ok(!t[`figure.text.${key}`]!.includes('{part}'), `${lang} ${key}`)
|
|
30
|
+
/* No particle or bracket stuck to a placeholder in the placement refusal: the parts are listed after a colon. */
|
|
31
|
+
assert.deepEqual(t['figure.text.placement-plane-refused']!.match(/\{[a-z]+\}/g), ['{parts}'], lang)
|
|
32
|
+
assert.ok(!('figure.text.fasten-editing' in t), `${lang}: a key no screen says is not kept`)
|
|
33
|
+
}
|
|
22
34
|
})
|