@things-factory/figure-ui 10.1.65 → 10.1.67
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/client/graphql/index.ts +0 -45
- package/client/modeller/figure-history-panel.ts +6 -145
- package/client/modeller/figure-v3-capability.ts +2 -2
- package/client/modeller/figure-v3-clips.ts +2 -2
- package/client/modeller/figure-v3-controls.ts +2 -2
- package/client/modeller/figure-v3-first-save.ts +1 -1
- package/client/modeller/figure-v3-links.ts +6 -6
- package/client/modeller/figure-v3-material.ts +11 -11
- package/client/modeller/figure-v3-parts.ts +7 -10
- package/client/modeller/figure-v3-preview.ts +3 -3
- package/client/modeller/figure-v3-properties.ts +5 -6
- package/client/modeller/figure-v3-verdict.ts +9 -10
- package/client/modeller/figure-view.ts +2 -3
- package/client/modeller/modeller-route.ts +2 -3
- package/client/modeller/scene-budget.ts +0 -14
- package/client/modeller/side-panel-styles.ts +5 -5
- package/client/modeller/v3-align.ts +16 -6
- package/client/modeller/v3-canvas.ts +12 -12
- package/client/modeller/v3-clips.ts +1 -1
- package/client/modeller/v3-controls.ts +1 -1
- package/client/modeller/v3-editor.ts +21 -21
- package/client/modeller/v3-fields.ts +1 -1
- package/client/modeller/v3-figure-facts.ts +1 -1
- package/client/modeller/v3-first-save.ts +3 -4
- package/client/modeller/v3-gizmo.ts +5 -5
- package/client/modeller/v3-help.ts +1 -1
- package/client/modeller/v3-joint-fan.ts +4 -5
- package/client/modeller/v3-keys.ts +1 -1
- package/client/modeller/v3-links.ts +9 -12
- package/client/modeller/v3-maturity.ts +22 -26
- package/client/modeller/v3-refusals.ts +17 -0
- package/client/modeller/v3-renderer.ts +1 -1
- package/client/modeller/v3-stage-model.ts +2 -2
- package/client/modeller/v3-thumbnail.ts +1 -3
- package/client/pages/figure-v3-modeller-page.ts +8 -11
- package/client/types.ts +2 -31
- package/dist-client/graphql/index.js +0 -45
- package/dist-client/graphql/index.js.map +1 -1
- package/dist-client/modeller/figure-history-panel.d.ts +4 -37
- package/dist-client/modeller/figure-history-panel.js +8 -154
- package/dist-client/modeller/figure-history-panel.js.map +1 -1
- package/dist-client/modeller/figure-v3-capability.d.ts +1 -1
- package/dist-client/modeller/figure-v3-capability.js +1 -1
- package/dist-client/modeller/figure-v3-capability.js.map +1 -1
- package/dist-client/modeller/figure-v3-clips.d.ts +2 -2
- package/dist-client/modeller/figure-v3-clips.js +2 -2
- package/dist-client/modeller/figure-v3-clips.js.map +1 -1
- package/dist-client/modeller/figure-v3-controls.d.ts +1 -1
- package/dist-client/modeller/figure-v3-controls.js +2 -2
- package/dist-client/modeller/figure-v3-controls.js.map +1 -1
- package/dist-client/modeller/figure-v3-first-save.d.ts +1 -1
- package/dist-client/modeller/figure-v3-first-save.js +1 -1
- package/dist-client/modeller/figure-v3-first-save.js.map +1 -1
- package/dist-client/modeller/figure-v3-links.d.ts +5 -5
- package/dist-client/modeller/figure-v3-links.js +6 -6
- package/dist-client/modeller/figure-v3-links.js.map +1 -1
- package/dist-client/modeller/figure-v3-material.d.ts +6 -6
- package/dist-client/modeller/figure-v3-material.js +11 -11
- package/dist-client/modeller/figure-v3-material.js.map +1 -1
- package/dist-client/modeller/figure-v3-parts.d.ts +6 -8
- package/dist-client/modeller/figure-v3-parts.js +1 -1
- package/dist-client/modeller/figure-v3-parts.js.map +1 -1
- package/dist-client/modeller/figure-v3-preview.js.map +1 -1
- package/dist-client/modeller/figure-v3-properties.d.ts +4 -5
- package/dist-client/modeller/figure-v3-properties.js +5 -6
- package/dist-client/modeller/figure-v3-properties.js.map +1 -1
- package/dist-client/modeller/figure-v3-verdict.d.ts +2 -2
- package/dist-client/modeller/figure-v3-verdict.js +9 -10
- package/dist-client/modeller/figure-v3-verdict.js.map +1 -1
- package/dist-client/modeller/figure-view.d.ts +2 -3
- package/dist-client/modeller/figure-view.js.map +1 -1
- package/dist-client/modeller/modeller-route.d.ts +2 -3
- package/dist-client/modeller/modeller-route.js +2 -3
- package/dist-client/modeller/modeller-route.js.map +1 -1
- package/dist-client/modeller/scene-budget.d.ts +0 -11
- package/dist-client/modeller/scene-budget.js +0 -12
- package/dist-client/modeller/scene-budget.js.map +1 -1
- package/dist-client/modeller/side-panel-styles.d.ts +2 -2
- package/dist-client/modeller/side-panel-styles.js +5 -5
- package/dist-client/modeller/side-panel-styles.js.map +1 -1
- package/dist-client/modeller/v3-align.d.ts +9 -5
- package/dist-client/modeller/v3-align.js +13 -3
- package/dist-client/modeller/v3-align.js.map +1 -1
- package/dist-client/modeller/v3-canvas.d.ts +4 -4
- package/dist-client/modeller/v3-canvas.js +9 -9
- package/dist-client/modeller/v3-canvas.js.map +1 -1
- package/dist-client/modeller/v3-clips.js.map +1 -1
- package/dist-client/modeller/v3-controls.js.map +1 -1
- package/dist-client/modeller/v3-editor.d.ts +13 -13
- package/dist-client/modeller/v3-editor.js +19 -18
- package/dist-client/modeller/v3-editor.js.map +1 -1
- package/dist-client/modeller/v3-fields.js.map +1 -1
- package/dist-client/modeller/v3-figure-facts.d.ts +1 -1
- package/dist-client/modeller/v3-figure-facts.js +1 -1
- package/dist-client/modeller/v3-figure-facts.js.map +1 -1
- package/dist-client/modeller/v3-first-save.js +3 -4
- package/dist-client/modeller/v3-first-save.js.map +1 -1
- package/dist-client/modeller/v3-gizmo.d.ts +5 -5
- package/dist-client/modeller/v3-gizmo.js +1 -1
- package/dist-client/modeller/v3-gizmo.js.map +1 -1
- package/dist-client/modeller/v3-help.d.ts +1 -1
- package/dist-client/modeller/v3-help.js +1 -1
- package/dist-client/modeller/v3-help.js.map +1 -1
- package/dist-client/modeller/v3-joint-fan.js +4 -5
- package/dist-client/modeller/v3-joint-fan.js.map +1 -1
- package/dist-client/modeller/v3-keys.js.map +1 -1
- package/dist-client/modeller/v3-links.d.ts +5 -7
- package/dist-client/modeller/v3-links.js +6 -8
- package/dist-client/modeller/v3-links.js.map +1 -1
- package/dist-client/modeller/v3-maturity.d.ts +7 -7
- package/dist-client/modeller/v3-maturity.js +20 -24
- package/dist-client/modeller/v3-maturity.js.map +1 -1
- package/dist-client/modeller/v3-refusals.d.ts +6 -0
- package/dist-client/modeller/v3-refusals.js +18 -0
- package/dist-client/modeller/v3-refusals.js.map +1 -1
- package/dist-client/modeller/v3-renderer.js +1 -1
- package/dist-client/modeller/v3-renderer.js.map +1 -1
- package/dist-client/modeller/v3-stage-model.js.map +1 -1
- package/dist-client/modeller/v3-thumbnail.js +1 -3
- package/dist-client/modeller/v3-thumbnail.js.map +1 -1
- package/dist-client/pages/figure-v3-modeller-page.d.ts +4 -5
- package/dist-client/pages/figure-v3-modeller-page.js +8 -11
- package/dist-client/pages/figure-v3-modeller-page.js.map +1 -1
- package/dist-client/route.d.ts +1 -1
- package/dist-client/tsconfig.fui.tsbuildinfo +1 -1
- package/dist-client/tsconfig.tsbuildinfo +1 -1
- package/dist-client/types.d.ts +2 -29
- package/dist-client/types.js +3 -0
- package/dist-client/types.js.map +1 -1
- package/docs/v3-product-cutover.md +14 -24
- package/package.json +5 -5
- package/test/browser/modeller-page.js +6 -7
- package/test/browser/modeller.check.mjs +9 -16
- package/test/fixtures/joint-column.json +1138 -0
- package/test/fixtures/joint-roller.json +872 -0
- package/test/fixtures/robot-arm-6dof.json +2776 -0
- package/test/i18n-prefix-guard.test.ts +0 -31
- package/test/modeller-route.test.ts +2 -3
- package/test/v3-align.test.ts +9 -4
- package/test/v3-clips.test.ts +1 -1
- package/test/v3-controls.test.ts +1 -1
- package/test/v3-fields.test.ts +4 -4
- package/test/v3-first-save.test.ts +1 -1
- package/test/v3-gizmo.test.ts +5 -5
- package/test/v3-joint-fan.test.ts +12 -42
- package/test/v3-keys.test.ts +1 -1
- package/test/v3-layout.test.ts +4 -5
- package/test/v3-links.test.ts +3 -3
- package/test/v3-material.test.ts +3 -3
- package/test/v3-maturity.test.ts +8 -9
- package/test/v3-parts-wiring.test.ts +3 -3
- package/test/v3-preview.test.ts +1 -1
- package/test/v3-product-write.test.ts +1 -1
- package/test/v3-properties.test.ts +3 -3
- package/test/v3-refusals.test.ts +12 -0
- package/test/v3-release-panel.test.ts +5 -5
- package/test/v3-scene-canvas.test.ts +2 -2
- package/test/v3-theme.test.ts +2 -2
- package/test/v3-verdict.test.ts +2 -2
- package/test/v3-view.test.ts +2 -2
- package/translations/en.json +2 -143
- package/translations/ja.json +2 -143
- package/translations/ko.json +2 -143
- package/translations/ms.json +2 -143
- package/translations/zh.json +2 -143
- package/client/modeller/figure-source.ts +0 -437
- package/client/modeller/part-edits.ts +0 -312
- package/dist-client/modeller/figure-source.d.ts +0 -238
- package/dist-client/modeller/figure-source.js +0 -193
- package/dist-client/modeller/figure-source.js.map +0 -1
- package/dist-client/modeller/part-edits.d.ts +0 -89
- package/dist-client/modeller/part-edits.js +0 -270
- package/dist-client/modeller/part-edits.js.map +0 -1
- package/test/expect.ts +0 -57
- package/test/figure-source.test.ts +0 -511
- package/test/part-edits.test.ts +0 -350
package/test/part-edits.test.ts
DELETED
|
@@ -1,350 +0,0 @@
|
|
|
1
|
-
import assert from 'node:assert/strict'
|
|
2
|
-
import { describe, it, test } from 'node:test'
|
|
3
|
-
import { readFileSync } from 'node:fs'
|
|
4
|
-
import { fileURLToPath } from 'node:url'
|
|
5
|
-
|
|
6
|
-
import { expect } from './expect.ts'
|
|
7
|
-
|
|
8
|
-
import {
|
|
9
|
-
addPart,
|
|
10
|
-
alignPartToEnd,
|
|
11
|
-
alignPartToStart,
|
|
12
|
-
canMirror,
|
|
13
|
-
centerPart,
|
|
14
|
-
duplicatePart,
|
|
15
|
-
gridStep,
|
|
16
|
-
mirrorPart,
|
|
17
|
-
movePart,
|
|
18
|
-
newPart,
|
|
19
|
-
niceStep,
|
|
20
|
-
partLimit,
|
|
21
|
-
removePart,
|
|
22
|
-
roundPart,
|
|
23
|
-
snapPart,
|
|
24
|
-
updatePart
|
|
25
|
-
} from '../client/modeller/part-edits.ts'
|
|
26
|
-
import { toFigureSource } from '../dist-client/modeller/figure-source.js'
|
|
27
|
-
import type { FigureDraft, PartModel } from '../dist-client/modeller/figure-source.js'
|
|
28
|
-
import { validate } from '@hatiolab/figure-model'
|
|
29
|
-
|
|
30
|
-
/**
|
|
31
|
-
* 씬 모델 용어로 부품을 편집하는 규칙.
|
|
32
|
-
*
|
|
33
|
-
* 편집 중의 기준 데이터는 씬 모델이므로 편집도 씬의 용어로 한다. 그런데 저장되는 것은
|
|
34
|
-
* FigureSource 다. 그래서 두 가지를 확인한다 — **씬 용어에서 규칙이 맞는지**, 그리고
|
|
35
|
-
* **변환했을 때 검증을 통과하는지**. 앞의 것만 보면 화면에서는 멀쩡한데 저장이 거부되는
|
|
36
|
-
* 상황이 생긴다.
|
|
37
|
-
*/
|
|
38
|
-
|
|
39
|
-
/** 기준 상자 3000 x 2000 x 800 — 세 축이 모두 달라야 축을 바꿔 써도 테스트가 잡아낸다. */
|
|
40
|
-
const DRAFT: FigureDraft = {
|
|
41
|
-
width: 3000,
|
|
42
|
-
height: 2000,
|
|
43
|
-
depth: 800,
|
|
44
|
-
figureType: 'AGV',
|
|
45
|
-
detailLevel: 'L'
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
const DECK: PartModel = {
|
|
49
|
-
type: 'figure-part',
|
|
50
|
-
name: 'deck',
|
|
51
|
-
primitive: 'cube',
|
|
52
|
-
left: 1200,
|
|
53
|
-
top: 900,
|
|
54
|
-
width: 800,
|
|
55
|
-
height: 600,
|
|
56
|
-
zPos: 500,
|
|
57
|
-
depth: 200,
|
|
58
|
-
token: 'palette.primary'
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
/*
|
|
62
|
-
* 기즈모에서 온 숫자.
|
|
63
|
-
*
|
|
64
|
-
* 화면에서 끌면 씬이 비율을 곱한 값을 돌려준다. 그 값이 그대로 부품에 들어가면 저장 형식에
|
|
65
|
-
* 소수 넷째 자리가 남고, 크기 칸은 잘려서 보인다.
|
|
66
|
-
*/
|
|
67
|
-
describe('씬에서 온 부품을 밀리미터로 맞춘다', () => {
|
|
68
|
-
const part = (over: Partial<PartModel> = {}): PartModel => ({ ...DECK, ...over })
|
|
69
|
-
|
|
70
|
-
it('끈 크기와 자리를 정수로 맞춘다', () => {
|
|
71
|
-
const dragged = part({ left: 384.99999999999994, top: 380, zPos: 930, width: 368.98743869823886, height: 140, depth: 722.4180046035418 })
|
|
72
|
-
const fixed = roundPart(dragged)
|
|
73
|
-
|
|
74
|
-
expect(fixed.left).toBe(385)
|
|
75
|
-
expect(fixed.width).toBe(369)
|
|
76
|
-
expect(fixed.depth).toBe(722)
|
|
77
|
-
expect(fixed.top).toBe(380)
|
|
78
|
-
})
|
|
79
|
-
|
|
80
|
-
it('크기는 1 밑으로 안 내려간다 — 0 이면 부피가 사라지고 배율이 0 으로 나뉜다', () => {
|
|
81
|
-
const tiny = roundPart(part({ width: 0.2, height: 0.4, depth: 0 }))
|
|
82
|
-
expect(tiny.width).toBe(1)
|
|
83
|
-
expect(tiny.height).toBe(1)
|
|
84
|
-
expect(tiny.depth).toBe(1)
|
|
85
|
-
})
|
|
86
|
-
|
|
87
|
-
it('맞춘 값을 다시 맞춰도 같다', () => {
|
|
88
|
-
const once = roundPart(part({ left: 12.5, width: 7.5 }))
|
|
89
|
-
expect(roundPart(once)).toEqual(once)
|
|
90
|
-
})
|
|
91
|
-
|
|
92
|
-
it('크기·자리 밖의 값은 건드리지 않는다', () => {
|
|
93
|
-
const kept = roundPart(part({ name: 'arm', token: 'palette.dark', segments: 12, zPos: 3.4 }))
|
|
94
|
-
expect(kept.name).toBe('arm')
|
|
95
|
-
expect(kept.token).toBe('palette.dark')
|
|
96
|
-
expect(kept.segments).toBe(12)
|
|
97
|
-
expect(kept.zPos).toBe(3)
|
|
98
|
-
})
|
|
99
|
-
})
|
|
100
|
-
|
|
101
|
-
describe('부품 생성', () => {
|
|
102
|
-
it('기준 상자의 3분의 1 크기로 생성된다 — 추가하자마자 보여야 한다', () => {
|
|
103
|
-
const part = newPart(DRAFT, [], 'cube')
|
|
104
|
-
|
|
105
|
-
expect(part.width).toBe(1000)
|
|
106
|
-
expect(part.height).toBe(667)
|
|
107
|
-
expect(part.depth).toBe(267)
|
|
108
|
-
})
|
|
109
|
-
|
|
110
|
-
it('바닥 가운데에 놓인다', () => {
|
|
111
|
-
const part = newPart(DRAFT, [], 'cube')
|
|
112
|
-
|
|
113
|
-
expect(part.zPos).toBe(0)
|
|
114
|
-
// 위치도 크기도 정수로 맞추므로 0.5 까지는 어긋난다
|
|
115
|
-
expect(Math.abs(part.left + part.width / 2 - DRAFT.width / 2)).toBeLessThanOrEqual(0.5)
|
|
116
|
-
expect(Math.abs(part.top + part.height / 2 - DRAFT.height / 2)).toBeLessThanOrEqual(0.5)
|
|
117
|
-
})
|
|
118
|
-
|
|
119
|
-
it('편집 캔버스에 그대로 놓을 수 있는 씬 컴포넌트 타입을 갖는다', () => {
|
|
120
|
-
expect(newPart(DRAFT, [], 'cube').type).toBe('figure-part')
|
|
121
|
-
})
|
|
122
|
-
|
|
123
|
-
it('이름이 중복되지 않는다 — 저장되는 식별자다', () => {
|
|
124
|
-
let parts: PartModel[] = []
|
|
125
|
-
for (let i = 0; i < 3; i++) parts = addPart(DRAFT, parts, 'cube')
|
|
126
|
-
|
|
127
|
-
expect(parts.map(part => part.name)).toEqual(['cube', 'cube-2', 'cube-3'])
|
|
128
|
-
})
|
|
129
|
-
|
|
130
|
-
it('팔레트 토큰을 기존 부품에서 물려받는다 — 토큰이 늘면 재질 그룹이 하나씩 는다', () => {
|
|
131
|
-
const parts = addPart(DRAFT, [{ ...DECK, token: 'palette.dark' }], 'sphere')
|
|
132
|
-
expect(parts[1].token).toBe('palette.dark')
|
|
133
|
-
})
|
|
134
|
-
|
|
135
|
-
it('곡면 도형은 분할 수를 갖고 생성된다', () => {
|
|
136
|
-
expect(newPart(DRAFT, [], 'cylinder').segments).toBe(12)
|
|
137
|
-
expect(newPart(DRAFT, [], 'cube').segments).toBeUndefined()
|
|
138
|
-
})
|
|
139
|
-
|
|
140
|
-
it('polygon 은 삼각형으로 생성된다 — 점이 3개보다 적으면 검증에서 막힌다', () => {
|
|
141
|
-
expect(newPart(DRAFT, [], 'polygon').path).toHaveLength(3)
|
|
142
|
-
})
|
|
143
|
-
|
|
144
|
-
/*
|
|
145
|
-
* 둘째 부품이 어디에 서는가.
|
|
146
|
-
*
|
|
147
|
-
* 언제나 바닥 한가운데였을 때, 둘째 부품은 첫 부품 **속에** 들어갔다 — 같은 자리에 같은
|
|
148
|
-
* 크기라 화면에는 덩어리 하나뿐이고 저작자는 무엇이 늘었는지 못 봤다.
|
|
149
|
-
*/
|
|
150
|
-
describe('고른 부품 위에 얹는다', () => {
|
|
151
|
-
/* 갑판을 바닥에 내려 둔다 — 그 위에 3분의 1 짜리가 들어가야 얹는 갈래를 볼 수 있다. */
|
|
152
|
-
const FLOOR_DECK = { ...DECK, zPos: 0 }
|
|
153
|
-
|
|
154
|
-
it('윗면에 서고 발자국이 가운데로 맞는다', () => {
|
|
155
|
-
const part = newPart(DRAFT, [FLOOR_DECK], 'cube', FLOOR_DECK)
|
|
156
|
-
|
|
157
|
-
expect(part.zPos).toBe(FLOOR_DECK.zPos + FLOOR_DECK.depth)
|
|
158
|
-
// 자리도 크기도 정수로 맞추므로 0.5 까지는 어긋난다
|
|
159
|
-
const middle = { x: FLOOR_DECK.left + FLOOR_DECK.width / 2, y: FLOOR_DECK.top + FLOOR_DECK.height / 2 }
|
|
160
|
-
expect(Math.abs(part.left + part.width / 2 - middle.x)).toBeLessThanOrEqual(0.5)
|
|
161
|
-
expect(Math.abs(part.top + part.height / 2 - middle.y)).toBeLessThanOrEqual(0.5)
|
|
162
|
-
})
|
|
163
|
-
|
|
164
|
-
it('얹으면 상자를 넘을 때는 바닥 한가운데로 간다 — 추가가 발행을 막지 않는다', () => {
|
|
165
|
-
/* 갑판이 이미 높다: 500 + 200 위에 267 을 더 쌓으면 상자 높이 800 을 넘는다. */
|
|
166
|
-
const part = newPart(DRAFT, [DECK], 'cube', DECK)
|
|
167
|
-
|
|
168
|
-
expect(part.zPos).toBe(0)
|
|
169
|
-
expect(Math.abs(part.left + part.width / 2 - DRAFT.width / 2)).toBeLessThanOrEqual(0.5)
|
|
170
|
-
})
|
|
171
|
-
|
|
172
|
-
it('가장자리 부품 위에서도 상자 안에 남는다', () => {
|
|
173
|
-
const corner = { ...DECK, left: 0, top: 0, width: 200, height: 200, zPos: 0, depth: 100 }
|
|
174
|
-
const part = newPart(DRAFT, [corner], 'cube', corner)
|
|
175
|
-
|
|
176
|
-
expect(part.left).toBe(0)
|
|
177
|
-
expect(part.top).toBe(0)
|
|
178
|
-
expect(part.left + part.width).toBeLessThanOrEqual(DRAFT.width)
|
|
179
|
-
expect(part.top + part.height).toBeLessThanOrEqual(DRAFT.height)
|
|
180
|
-
})
|
|
181
|
-
|
|
182
|
-
it('고른 것이 없으면 전과 같이 바닥 한가운데다', () => {
|
|
183
|
-
const alone = newPart(DRAFT, [DECK], 'cube')
|
|
184
|
-
expect(alone.zPos).toBe(0)
|
|
185
|
-
expect(Math.abs(alone.left + alone.width / 2 - DRAFT.width / 2)).toBeLessThanOrEqual(0.5)
|
|
186
|
-
})
|
|
187
|
-
|
|
188
|
-
it('쌓은 둘이 서로 겹치지 않는다 — 이 규칙이 지키는 것이 그것이다', () => {
|
|
189
|
-
const [, stacked] = addPart(DRAFT, [FLOOR_DECK], 'cylinder', FLOOR_DECK)
|
|
190
|
-
expect(stacked!.zPos).toBeGreaterThanOrEqual(FLOOR_DECK.zPos + FLOOR_DECK.depth)
|
|
191
|
-
})
|
|
192
|
-
})
|
|
193
|
-
|
|
194
|
-
/*
|
|
195
|
-
화면에서 멀쩡해 보여도 저장이 거부되면 사용자는 이유를 알 수 없다. 새로 만든 부품은
|
|
196
|
-
손대지 않은 상태로도 검증을 통과해야 한다.
|
|
197
|
-
*/
|
|
198
|
-
it('새로 만든 부품만으로도 검증을 통과한다', () => {
|
|
199
|
-
for (const kind of ['cube', 'wall', 'cylinder', 'sphere', 'rect', 'polygon'] as const) {
|
|
200
|
-
const source = toFigureSource(DRAFT, [newPart(DRAFT, [], kind)])
|
|
201
|
-
expect(validate(source).errors).toEqual([])
|
|
202
|
-
}
|
|
203
|
-
})
|
|
204
|
-
})
|
|
205
|
-
|
|
206
|
-
describe('목록 편집', () => {
|
|
207
|
-
const PARTS = [DECK, { ...DECK, name: 'mast' }, { ...DECK, name: 'wheel' }]
|
|
208
|
-
|
|
209
|
-
it('삭제한 것만 빠진다', () => {
|
|
210
|
-
expect(removePart(PARTS, 1).map(part => part.name)).toEqual(['deck', 'wheel'])
|
|
211
|
-
})
|
|
212
|
-
|
|
213
|
-
it('복제본이 바로 뒤에 오고 이름이 새로 붙는다', () => {
|
|
214
|
-
const next = duplicatePart(PARTS, 0)
|
|
215
|
-
expect(next.map(part => part.name)).toEqual(['deck', 'deck-copy', 'mast', 'wheel'])
|
|
216
|
-
})
|
|
217
|
-
|
|
218
|
-
it('복제본이 원본과 객체를 공유하지 않는다 — 수정하면 따로 움직여야 한다', () => {
|
|
219
|
-
const next = duplicatePart([{ ...DECK, path: [{ x: 0, y: 0 }] }], 0)
|
|
220
|
-
next[1].path![0].x = 99
|
|
221
|
-
|
|
222
|
-
expect(next[0].path![0].x).toBe(0)
|
|
223
|
-
})
|
|
224
|
-
|
|
225
|
-
it('순서를 바꾼다', () => {
|
|
226
|
-
expect(movePart(PARTS, 2, 0).map(part => part.name)).toEqual(['wheel', 'deck', 'mast'])
|
|
227
|
-
})
|
|
228
|
-
|
|
229
|
-
it('범위를 벗어나면 그대로 둔다', () => {
|
|
230
|
-
expect(movePart(PARTS, 0, -1)).toBe(PARTS)
|
|
231
|
-
expect(movePart(PARTS, 2, 3)).toBe(PARTS)
|
|
232
|
-
})
|
|
233
|
-
|
|
234
|
-
it('원본을 수정하지 않는다', () => {
|
|
235
|
-
const before = JSON.stringify(PARTS)
|
|
236
|
-
removePart(PARTS, 0)
|
|
237
|
-
duplicatePart(PARTS, 0)
|
|
238
|
-
updatePart(PARTS, 0, { ...DECK, left: 0 })
|
|
239
|
-
|
|
240
|
-
expect(JSON.stringify(PARTS)).toBe(before)
|
|
241
|
-
})
|
|
242
|
-
|
|
243
|
-
it('부품 수 한도는 디테일 등급이 결정한다', () => {
|
|
244
|
-
expect(partLimit({ ...DRAFT, detailLevel: 'S' })).toBeLessThan(partLimit({ ...DRAFT, detailLevel: 'L' }))
|
|
245
|
-
})
|
|
246
|
-
})
|
|
247
|
-
|
|
248
|
-
/*
|
|
249
|
-
정밀 배치 도구.
|
|
250
|
-
|
|
251
|
-
씬 모델은 원점이 **모서리**다(left·top 이 0 에서 시작하고 zPos 는 밑면이다).
|
|
252
|
-
FigureSource 는 원점이 중심이다. 이전 구현은 FigureSource 기준이라 '가운데로'가 곧
|
|
253
|
-
'0 으로'였는데, 씬 용어에서는 그렇지 않다 — 이 절이 그 차이를 확인한다.
|
|
254
|
-
*/
|
|
255
|
-
describe('정밀 배치 도구', () => {
|
|
256
|
-
it('가운데로 옮기면 변환했을 때 원점에 온다', () => {
|
|
257
|
-
const moved = centerPart(DRAFT, [{ ...DECK, left: 0 }], 0, 'x')
|
|
258
|
-
|
|
259
|
-
expect(moved[0].left).toBe(1100)
|
|
260
|
-
expect(toFigureSource(DRAFT, moved).parts[0].transform.position.x).toBe(0)
|
|
261
|
-
})
|
|
262
|
-
|
|
263
|
-
it('축마다 다른 속성을 바꾼다 — z 는 top 이고 y 는 zPos 다', () => {
|
|
264
|
-
expect(centerPart(DRAFT, [DECK], 0, 'z')[0].top).toBe(700)
|
|
265
|
-
expect(centerPart(DRAFT, [DECK], 0, 'y')[0].zPos).toBe(300)
|
|
266
|
-
})
|
|
267
|
-
|
|
268
|
-
it('바닥에 붙이면 zPos 가 0 이다 — 밑면이 곧 상자 바닥이다', () => {
|
|
269
|
-
expect(alignPartToStart([DECK], 0, 'y')[0].zPos).toBe(0)
|
|
270
|
-
})
|
|
271
|
-
|
|
272
|
-
it('끝에 붙이면 부품의 끝이 상자의 끝과 만난다', () => {
|
|
273
|
-
const moved = alignPartToEnd(DRAFT, [DECK], 0, 'x')
|
|
274
|
-
expect(moved[0].left + moved[0].width).toBe(DRAFT.width)
|
|
275
|
-
})
|
|
276
|
-
|
|
277
|
-
it('대칭 복제가 상자 안에서 반대쪽으로 간다', () => {
|
|
278
|
-
const parts = mirrorPart(DRAFT, [{ ...DECK, left: 200 }], 0, 'x')
|
|
279
|
-
|
|
280
|
-
expect(parts).toHaveLength(2)
|
|
281
|
-
// 왼쪽 여백 200 → 오른쪽 여백도 200 이어야 한다
|
|
282
|
-
expect(parts[1].left).toBe(DRAFT.width - 200 - DECK.width)
|
|
283
|
-
})
|
|
284
|
-
|
|
285
|
-
it('대칭 복제본이 어느 쪽인지 이름에 드러난다', () => {
|
|
286
|
-
expect(mirrorPart(DRAFT, [{ ...DECK, left: 200 }], 0, 'x')[1].name).toBe('deck-x')
|
|
287
|
-
})
|
|
288
|
-
|
|
289
|
-
it('대칭 복제가 원본을 건드리지 않는다', () => {
|
|
290
|
-
const parts = mirrorPart(DRAFT, [{ ...DECK, left: 200 }], 0, 'x')
|
|
291
|
-
expect(parts[0].left).toBe(200)
|
|
292
|
-
})
|
|
293
|
-
|
|
294
|
-
/*
|
|
295
|
-
이미 가운데면 사본이 같은 자리에 생긴다. 화면에는 아무 변화가 없어 보이는데 부품 수만
|
|
296
|
-
늘고 겹친 면에서 z-fighting 이 일어난다.
|
|
297
|
-
*/
|
|
298
|
-
it('이미 가운데면 대칭 복제를 막는다', () => {
|
|
299
|
-
const centered = centerPart(DRAFT, [DECK], 0, 'x')
|
|
300
|
-
|
|
301
|
-
expect(canMirror(DRAFT, centered, 0, 'x')).toBe(false)
|
|
302
|
-
expect(mirrorPart(DRAFT, centered, 0, 'x')).toHaveLength(1)
|
|
303
|
-
})
|
|
304
|
-
|
|
305
|
-
it('가운데가 아니면 대칭 복제할 수 있다', () => {
|
|
306
|
-
expect(canMirror(DRAFT, [{ ...DECK, left: 200 }], 0, 'x')).toBe(true)
|
|
307
|
-
})
|
|
308
|
-
|
|
309
|
-
it('격자에 맞추면 위치와 크기가 격자 배수가 된다', () => {
|
|
310
|
-
const step = gridStep(DRAFT)
|
|
311
|
-
const snapped = snapPart(DRAFT, [{ ...DECK, left: 1213, width: 787 }], 0)
|
|
312
|
-
|
|
313
|
-
expect(snapped[0].left % step).toBe(0)
|
|
314
|
-
expect(snapped[0].width % step).toBe(0)
|
|
315
|
-
})
|
|
316
|
-
|
|
317
|
-
it('격자에 맞춰도 크기가 0 이 되지 않는다 — 사라진 것처럼 보인다', () => {
|
|
318
|
-
const snapped = snapPart(DRAFT, [{ ...DECK, width: 1, height: 1, depth: 1 }], 0)
|
|
319
|
-
|
|
320
|
-
expect(snapped[0].width).toBeGreaterThan(0)
|
|
321
|
-
expect(snapped[0].height).toBeGreaterThan(0)
|
|
322
|
-
expect(snapped[0].depth).toBeGreaterThan(0)
|
|
323
|
-
})
|
|
324
|
-
|
|
325
|
-
it('없는 인덱스를 주면 목록을 그대로 반환한다', () => {
|
|
326
|
-
const parts = [DECK]
|
|
327
|
-
expect(centerPart(DRAFT, parts, 7, 'x')).toBe(parts)
|
|
328
|
-
expect(snapPart(DRAFT, parts, 7)).toBe(parts)
|
|
329
|
-
expect(mirrorPart(DRAFT, parts, 7, 'x')).toBe(parts)
|
|
330
|
-
expect(canMirror(DRAFT, parts, 7, 'x')).toBe(false)
|
|
331
|
-
})
|
|
332
|
-
})
|
|
333
|
-
|
|
334
|
-
describe('격자 간격', () => {
|
|
335
|
-
it('읽기 좋은 값이 나온다 — 27·33 같은 간격은 좌표를 읽을 수 없게 만든다', () => {
|
|
336
|
-
expect(niceStep(3000)).toBe(500)
|
|
337
|
-
expect(niceStep(1000)).toBe(200)
|
|
338
|
-
expect(niceStep(137)).toBe(20)
|
|
339
|
-
expect(niceStep(4)).toBe(1)
|
|
340
|
-
})
|
|
341
|
-
|
|
342
|
-
it('아무리 작아도 0 이 되지 않는다 — 0 으로 나누면 NaN 이 된다', () => {
|
|
343
|
-
expect(niceStep(0)).toBeGreaterThan(0)
|
|
344
|
-
expect(niceStep(-100)).toBeGreaterThan(0)
|
|
345
|
-
})
|
|
346
|
-
|
|
347
|
-
it('기준 상자의 긴 쪽을 기준으로 잡는다 — 3D 바닥 격자와 같아야 한다', () => {
|
|
348
|
-
expect(gridStep(DRAFT)).toBe(niceStep(3000))
|
|
349
|
-
})
|
|
350
|
-
})
|