@hatiolab/figure-model 0.1.76 → 0.1.77
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/CHANGELOG.md +11 -0
- package/README.md +60 -138
- package/dist/index.d.ts +1 -13
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -26
- package/dist/index.js.map +1 -1
- package/dist/v3-asset-types.d.ts +1 -2
- package/dist/v3-asset-types.d.ts.map +1 -1
- package/dist/v3-asset.js +1 -1
- package/dist/v3-asset.js.map +1 -1
- package/dist/v3-authoring-actions.d.ts +9 -12
- package/dist/v3-authoring-actions.d.ts.map +1 -1
- package/dist/v3-authoring-actions.js +4 -5
- package/dist/v3-authoring-actions.js.map +1 -1
- package/dist/v3-capabilities.js +4 -1
- package/dist/v3-capabilities.js.map +1 -1
- package/dist/v3-cost.d.ts.map +1 -1
- package/dist/v3-cost.js +3 -5
- package/dist/v3-cost.js.map +1 -1
- package/dist/v3-create.d.ts +1 -1
- package/dist/v3-create.d.ts.map +1 -1
- package/dist/v3-examples.js +1 -1
- package/dist/v3-gate.d.ts +7 -8
- package/dist/v3-gate.d.ts.map +1 -1
- package/dist/v3-gate.js +11 -14
- package/dist/v3-gate.js.map +1 -1
- package/dist/v3-graph.d.ts +1 -2
- package/dist/v3-graph.d.ts.map +1 -1
- package/dist/v3-graph.js +5 -7
- package/dist/v3-graph.js.map +1 -1
- package/dist/v3-instance-size.d.ts +3 -5
- package/dist/v3-instance-size.d.ts.map +1 -1
- package/dist/v3-instance-size.js +2 -4
- package/dist/v3-instance-size.js.map +1 -1
- package/dist/v3-kernel-version.d.ts +1 -1
- package/dist/v3-kernel-version.js +1 -1
- package/dist/v3-part-edit.d.ts +4 -5
- package/dist/v3-part-edit.d.ts.map +1 -1
- package/dist/v3-part-edit.js +2 -2
- package/dist/v3-part-edit.js.map +1 -1
- package/dist/v3-proposal.js +1 -1
- package/dist/v3-proposal.js.map +1 -1
- package/dist/v3-release-contract.js +1 -1
- package/dist/v3-release-contract.js.map +1 -1
- package/dist/v3-score.d.ts +4 -5
- package/dist/v3-score.d.ts.map +1 -1
- package/dist/v3-score.js +7 -8
- package/dist/v3-score.js.map +1 -1
- package/dist/v3-words.d.ts +87 -0
- package/dist/v3-words.d.ts.map +1 -0
- package/dist/v3-words.js +87 -0
- package/dist/v3-words.js.map +1 -0
- package/docs/assembly-constraints-v3.md +13 -23
- package/docs/v3-asset-persistence.md +4 -4
- package/docs/v3-common-kernel-experiment.md +1 -1
- package/docs/v3-core-semantics.md +3 -3
- package/docs/v3-cutover.md +5 -3
- package/docs/v3-design.md +13 -26
- package/docs/v3-editor-integration.md +2 -2
- package/docs/v3-full-conveyor-validation.md +3 -3
- package/docs/v3-layout-system.md +1 -1
- package/docs/v3-minimal-model.md +0 -1
- package/docs/v3-motion-contract.md +21 -56
- package/docs/v3-runtime-extraction.md +7 -7
- package/docs/v3-sample-validation-expanded.md +1 -1
- package/docs/v3-sample-validation.md +1 -1
- package/docs/v3-shape-dimension-contract.md +23 -57
- package/docs/v3-status.md +5 -5
- package/docs/v3-storage-integration.md +4 -4
- package/package.json +2 -20
- package/dist/blueprint-shape.d.ts +0 -10
- package/dist/blueprint-shape.d.ts.map +0 -1
- package/dist/blueprint-shape.js +0 -194
- package/dist/blueprint-shape.js.map +0 -1
- package/dist/blueprint.d.ts +0 -73
- package/dist/blueprint.d.ts.map +0 -1
- package/dist/blueprint.js +0 -388
- package/dist/blueprint.js.map +0 -1
- package/dist/cost-chart.d.ts +0 -35
- package/dist/cost-chart.d.ts.map +0 -1
- package/dist/cost-chart.js +0 -150
- package/dist/cost-chart.js.map +0 -1
- package/dist/cost.d.ts +0 -162
- package/dist/cost.d.ts.map +0 -1
- package/dist/cost.js +0 -194
- package/dist/cost.js.map +0 -1
- package/dist/gate.d.ts +0 -65
- package/dist/gate.d.ts.map +0 -1
- package/dist/gate.js +0 -284
- package/dist/gate.js.map +0 -1
- package/dist/grouping.d.ts +0 -121
- package/dist/grouping.d.ts.map +0 -1
- package/dist/grouping.js +0 -224
- package/dist/grouping.js.map +0 -1
- package/dist/keys.d.ts +0 -45
- package/dist/keys.d.ts.map +0 -1
- package/dist/keys.js +0 -84
- package/dist/keys.js.map +0 -1
- package/dist/origin.d.ts +0 -33
- package/dist/origin.d.ts.map +0 -1
- package/dist/origin.js +0 -46
- package/dist/origin.js.map +0 -1
- package/dist/release-contract.d.ts +0 -38
- package/dist/release-contract.d.ts.map +0 -1
- package/dist/release-contract.js +0 -246
- package/dist/release-contract.js.map +0 -1
- package/dist/sizing.d.ts +0 -231
- package/dist/sizing.d.ts.map +0 -1
- package/dist/sizing.js +0 -550
- package/dist/sizing.js.map +0 -1
- package/dist/types.d.ts +0 -1233
- package/dist/types.d.ts.map +0 -1
- package/dist/types.js +0 -547
- package/dist/types.js.map +0 -1
- package/dist/v3-from-v2.d.ts +0 -203
- package/dist/v3-from-v2.d.ts.map +0 -1
- package/dist/v3-from-v2.js +0 -2053
- package/dist/v3-from-v2.js.map +0 -1
- package/dist/v3-mesh-compare.d.ts +0 -24
- package/dist/v3-mesh-compare.d.ts.map +0 -1
- package/dist/v3-mesh-compare.js +0 -55
- package/dist/v3-mesh-compare.js.map +0 -1
- package/dist/validate.d.ts +0 -7
- package/dist/validate.d.ts.map +0 -1
- package/dist/validate.js +0 -1119
- package/dist/validate.js.map +0 -1
- package/dist/visual-evidence.d.ts +0 -21
- package/dist/visual-evidence.d.ts.map +0 -1
- package/dist/visual-evidence.js +0 -52
- package/dist/visual-evidence.js.map +0 -1
- package/docs/design.md +0 -193
- package/docs/format-survey.md +0 -108
- package/docs/format.md +0 -704
- package/docs/sizing.md +0 -183
- package/docs/validation.md +0 -357
package/dist/blueprint-shape.js
DELETED
|
@@ -1,194 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* 이미 **컴파일된 청사진**의 형태를 확인한다.
|
|
3
|
-
*
|
|
4
|
-
* `validate` 는 저작 형식(`FigureSource`)을 본다. 이쪽은 그 결과물인 `FigureBlueprint`
|
|
5
|
-
* 를 본다 — 서버나 파일에서 온 것이 이 형식대로 생겼는지, **읽기 전에 한 번** 묻는
|
|
6
|
-
* 자리다.
|
|
7
|
-
*
|
|
8
|
-
* 그리는 시점이 아니라 등록 시점에 보는 이유는, 잘못된 청사진이 프레임마다 조용히
|
|
9
|
-
* 실패하는 대신 등록에서 한 번 크게 실패하게 하려는 것이다.
|
|
10
|
-
*
|
|
11
|
-
* ## 왜 여기 있나
|
|
12
|
-
*
|
|
13
|
-
* 한동안 things-scene 이 이것을 손으로 들고 있었다. 「청사진이 어떻게 생겨야 하는가」는
|
|
14
|
-
* **형식의 지식**이고, 읽는 쪽이 다시 적으면 형식이 바뀔 때 조용히 어긋난다. 실제로
|
|
15
|
-
* `SEGMENT_PRESETS` 가 그렇게 갈려 있었다.
|
|
16
|
-
*
|
|
17
|
-
* 문제를 찾으면 사람이 읽을 수 있는 사유 목록을 돌려준다. 비어 있으면 읽을 수 있다.
|
|
18
|
-
*/
|
|
19
|
-
import { BLUEPRINT_VERSION, JOINT_TYPES, PART_ROLES } from "./types.js";
|
|
20
|
-
function isFiniteNumber(v) {
|
|
21
|
-
return typeof v === 'number' && Number.isFinite(v);
|
|
22
|
-
}
|
|
23
|
-
function isFiniteVec3(v) {
|
|
24
|
-
if (!v || typeof v !== 'object')
|
|
25
|
-
return false;
|
|
26
|
-
const { x, y, z } = v;
|
|
27
|
-
return isFiniteNumber(x) && isFiniteNumber(y) && isFiniteNumber(z);
|
|
28
|
-
}
|
|
29
|
-
/**
|
|
30
|
-
* 청사진의 형태를 확인한다 — **읽기 전에 한 번**, 등록 시점에.
|
|
31
|
-
*
|
|
32
|
-
* 그리는 시점이 아니라 등록 시점에 보는 이유는, 잘못된 청사진이 프레임마다 조용히
|
|
33
|
-
* 실패하는 대신 등록에서 한 번 크게 실패하게 하려는 것이다.
|
|
34
|
-
*
|
|
35
|
-
* 문제를 찾으면 사람이 읽을 수 있는 사유 목록을 돌려준다. 비어 있으면 읽을 수 있다.
|
|
36
|
-
*/
|
|
37
|
-
export function blueprintProblems(value) {
|
|
38
|
-
const problems = [];
|
|
39
|
-
const bp = value;
|
|
40
|
-
if (!bp || typeof bp !== 'object')
|
|
41
|
-
return ['청사진이 객체가 아니다'];
|
|
42
|
-
if (bp.version !== BLUEPRINT_VERSION) {
|
|
43
|
-
problems.push(`읽을 수 없는 판이다 — version ${String(bp.version)}, 이 판올림은 ${BLUEPRINT_VERSION} 만 읽는다`);
|
|
44
|
-
}
|
|
45
|
-
if (typeof bp.type !== 'string' || bp.type.length === 0) {
|
|
46
|
-
problems.push('type 이 없다 — 컴포넌트 타입 이름이 곧 청사진을 찾는 키다');
|
|
47
|
-
}
|
|
48
|
-
const base = bp.base;
|
|
49
|
-
if (!base || !isFiniteNumber(base.x) || !isFiniteNumber(base.y) || !isFiniteNumber(base.z)) {
|
|
50
|
-
problems.push('base 의 x·y·z 가 온전하지 않다');
|
|
51
|
-
}
|
|
52
|
-
else if (!(base.x > 0) || !(base.z > 0)) {
|
|
53
|
-
problems.push('base 의 x·z 는 0 보다 커야 한다 — 평면 배치 비율의 분모다');
|
|
54
|
-
}
|
|
55
|
-
if (!Array.isArray(bp.groups)) {
|
|
56
|
-
problems.push('groups 가 배열이 아니다');
|
|
57
|
-
return problems;
|
|
58
|
-
}
|
|
59
|
-
if (bp.groups.length === 0) {
|
|
60
|
-
problems.push('groups 가 비어 있다 — 그릴 것이 없는 청사진은 등록하지 않는다');
|
|
61
|
-
}
|
|
62
|
-
bp.groups.forEach((group, gi) => {
|
|
63
|
-
if (!group || !Array.isArray(group.members)) {
|
|
64
|
-
problems.push(`groups[${gi}].members 가 배열이 아니다`);
|
|
65
|
-
return;
|
|
66
|
-
}
|
|
67
|
-
if (group.members.length === 0) {
|
|
68
|
-
problems.push(`groups[${gi}] 에 부품이 없다`);
|
|
69
|
-
}
|
|
70
|
-
group.members.forEach((member, mi) => {
|
|
71
|
-
const where = `groups[${gi}].members[${mi}]`;
|
|
72
|
-
if (typeof member?.name !== 'string' || member.name.length === 0) {
|
|
73
|
-
problems.push(`${where}.name 이 없다 — 이름이 바인딩·이벤트·애니메이션이 붙는 자리다`);
|
|
74
|
-
}
|
|
75
|
-
const t = member?.transform;
|
|
76
|
-
if (!t || !isFiniteVec3(t.position) || !isFiniteVec3(t.size)) {
|
|
77
|
-
problems.push(`${where}.transform 의 값이 온전하지 않다`);
|
|
78
|
-
}
|
|
79
|
-
});
|
|
80
|
-
});
|
|
81
|
-
/*
|
|
82
|
-
자리와 문.
|
|
83
|
-
|
|
84
|
-
`groups` 와 달리 없어도 된다 — 능력을 안 지는 도형이 대부분이다. 있으면 형태를 본다.
|
|
85
|
-
그리지 않는 것이라 **틀려도 화면에는 아무 일도 안 일어나고**, 물건을 앉히려는 순간에야
|
|
86
|
-
프레임마다 조용히 실패한다. 등록에서 한 번 크게 실패하는 편이 낫다.
|
|
87
|
-
*/
|
|
88
|
-
if (bp.anchors !== undefined) {
|
|
89
|
-
if (!Array.isArray(bp.anchors)) {
|
|
90
|
-
problems.push('anchors 가 배열이 아니다');
|
|
91
|
-
}
|
|
92
|
-
else {
|
|
93
|
-
bp.anchors.forEach((at, ai) => {
|
|
94
|
-
const where = `anchors[${ai}]`;
|
|
95
|
-
if (typeof at?.name !== 'string' || at.name.length === 0) {
|
|
96
|
-
problems.push(`${where}.name 이 없다 — 이름이 곧 slot·port 의 id 다`);
|
|
97
|
-
}
|
|
98
|
-
if (!Array.isArray(at?.roles) || at.roles.length === 0) {
|
|
99
|
-
problems.push(`${where}.roles 가 역할 하나 이상의 배열이 아니다`);
|
|
100
|
-
}
|
|
101
|
-
else if (at.roles.some(role => !PART_ROLES.includes(role))) {
|
|
102
|
-
problems.push(`${where}.roles 에 ${PART_ROLES.join(' · ')} 밖의 값이 있다`);
|
|
103
|
-
}
|
|
104
|
-
const t = at?.transform;
|
|
105
|
-
if (!t || !isFiniteVec3(t.position) || !isFiniteVec3(t.size)) {
|
|
106
|
-
problems.push(`${where}.transform 의 값이 온전하지 않다`);
|
|
107
|
-
}
|
|
108
|
-
});
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
/*
|
|
112
|
-
값이 만드는 자세.
|
|
113
|
-
|
|
114
|
-
`anchors` 와 같은 갈래다 — 없어도 되고, **틀려도 세울 때는 아무 일도 안 일어난다.**
|
|
115
|
-
인스턴스가 값을 주는 순간에야 프레임마다 조용히 기본 자세로 돌아간다. 등록에서 한 번
|
|
116
|
-
크게 실패하는 편이 낫다.
|
|
117
|
-
|
|
118
|
-
`range` 를 여기서 보는 이유는 그것이 **런타임의 나누는 수**라서다. `max` 가 `min`
|
|
119
|
-
이하면 런타임이 물리량을 0~1 로 맵할 수 없고, 그러면 준 값이 조용히 버려진다.
|
|
120
|
-
*/
|
|
121
|
-
if (bp.parameters !== undefined) {
|
|
122
|
-
if (!Array.isArray(bp.parameters)) {
|
|
123
|
-
problems.push('parameters 가 배열이 아니다');
|
|
124
|
-
}
|
|
125
|
-
else {
|
|
126
|
-
bp.parameters.forEach((parameter, pi) => {
|
|
127
|
-
const where = `parameters[${pi}]`;
|
|
128
|
-
if (typeof parameter?.name !== 'string' || parameter.name.length === 0) {
|
|
129
|
-
problems.push(`${where}.name 이 없다 — 인스턴스가 이 이름으로 값을 준다`);
|
|
130
|
-
}
|
|
131
|
-
const range = parameter?.range;
|
|
132
|
-
if (!range || !isFiniteNumber(range.min) || !isFiniteNumber(range.max)) {
|
|
133
|
-
problems.push(`${where}.range 의 min·max 가 온전하지 않다`);
|
|
134
|
-
}
|
|
135
|
-
else if (!(range.max > range.min)) {
|
|
136
|
-
problems.push(`${where}.range 의 max 가 min 보다 크지 않다 — 0~1 로 맵할 수 없다`);
|
|
137
|
-
}
|
|
138
|
-
if (!parameter?.clip || !Array.isArray(parameter.clip.channels)) {
|
|
139
|
-
problems.push(`${where}.clip.channels 가 배열이 아니다 — 값이 무엇을 움직이는지 없다`);
|
|
140
|
-
}
|
|
141
|
-
else if (parameter.clip.duration !== undefined &&
|
|
142
|
-
!(isFiniteNumber(parameter.clip.duration) && parameter.clip.duration >= 0)) {
|
|
143
|
-
problems.push(`${where}.clip.duration 이 0 이상의 수가 아니다`);
|
|
144
|
-
}
|
|
145
|
-
});
|
|
146
|
-
}
|
|
147
|
-
}
|
|
148
|
-
/*
|
|
149
|
-
Joints (ADR-0066). Optional, like anchors. The runtime builds a node per joint and hangs groups from
|
|
150
|
-
the node a group names, so a group or anchor naming a joint that is not there, a zero axis, or a
|
|
151
|
-
parent that comes later would leave parts in no frame or turn them by nothing. Refused at
|
|
152
|
-
registration instead.
|
|
153
|
-
*/
|
|
154
|
-
if (bp.joints !== undefined) {
|
|
155
|
-
if (!Array.isArray(bp.joints)) {
|
|
156
|
-
problems.push('joints 가 배열이 아니다');
|
|
157
|
-
}
|
|
158
|
-
else {
|
|
159
|
-
const placed = new Set();
|
|
160
|
-
bp.joints.forEach((joint, ji) => {
|
|
161
|
-
const where = `joints[${ji}]`;
|
|
162
|
-
if (typeof joint?.name !== 'string' || joint.name.length === 0) {
|
|
163
|
-
problems.push(`${where}.name 이 없다 — channel 이 이 이름으로 관절을 몬다`);
|
|
164
|
-
return;
|
|
165
|
-
}
|
|
166
|
-
if (!JOINT_TYPES.includes(joint.type)) {
|
|
167
|
-
problems.push(`${where}.type 이 ${JOINT_TYPES.join(' · ')} 가 아니다`);
|
|
168
|
-
}
|
|
169
|
-
if (!isFiniteVec3(joint.origin))
|
|
170
|
-
problems.push(`${where}.origin 이 온전하지 않다`);
|
|
171
|
-
if (!isFiniteVec3(joint.axis) || Math.hypot(joint.axis.x, joint.axis.y, joint.axis.z) === 0) {
|
|
172
|
-
problems.push(`${where}.axis 가 0 이 아닌 벡터가 아니다`);
|
|
173
|
-
}
|
|
174
|
-
if (joint.parent !== undefined && !placed.has(joint.parent)) {
|
|
175
|
-
problems.push(`${where}.parent '${joint.parent}' 가 앞에 없다 — 관절은 부모가 먼저 온다`);
|
|
176
|
-
}
|
|
177
|
-
placed.add(joint.name);
|
|
178
|
-
});
|
|
179
|
-
}
|
|
180
|
-
}
|
|
181
|
-
const frames = new Set(Array.isArray(bp.joints) ? bp.joints.map(joint => joint?.name) : []);
|
|
182
|
-
bp.groups.forEach((group, gi) => {
|
|
183
|
-
if (group?.joint !== undefined && !frames.has(group.joint)) {
|
|
184
|
-
problems.push(`groups[${gi}].joint '${group.joint}' 가 joints 에 없다`);
|
|
185
|
-
}
|
|
186
|
-
});
|
|
187
|
-
(Array.isArray(bp.anchors) ? bp.anchors : []).forEach((at, ai) => {
|
|
188
|
-
if (at?.joint !== undefined && !frames.has(at.joint)) {
|
|
189
|
-
problems.push(`anchors[${ai}].joint '${at.joint}' 가 joints 에 없다`);
|
|
190
|
-
}
|
|
191
|
-
});
|
|
192
|
-
return problems;
|
|
193
|
-
}
|
|
194
|
-
//# sourceMappingURL=blueprint-shape.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"blueprint-shape.js","sourceRoot":"","sources":["../src/blueprint-shape.ts"],"names":[],"mappings":"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"}
|
package/dist/blueprint.d.ts
DELETED
|
@@ -1,73 +0,0 @@
|
|
|
1
|
-
import { type ValidateResult } from './validate.ts';
|
|
2
|
-
export { geometryKeyOf, emissiveKeyOf, materialKeyOf, usesSegments } from './keys.ts';
|
|
3
|
-
import { type FigureBlueprint, type FigurePart, type Axis, type PartTransform, type Vec3 } from './types.ts';
|
|
4
|
-
/** 컴파일할 수 없을 때 던진다. 오류보고없이 빈 청사진을 돌려주지 않는다. */
|
|
5
|
-
export declare class FigureCompileError extends Error {
|
|
6
|
-
readonly errors: ValidateResult['errors'];
|
|
7
|
-
constructor(errors: ValidateResult['errors']);
|
|
8
|
-
}
|
|
9
|
-
/**
|
|
10
|
-
* 삼각형 수 추정.
|
|
11
|
-
*
|
|
12
|
-
* 근거는 things-scene 의 geometry 생성 인자다.
|
|
13
|
-
*
|
|
14
|
-
* cube · wall BoxGeometry 면 6 × 2 = 12
|
|
15
|
-
* cylinder CylinderGeometry(seg) 측면 2·seg + 캡 2·seg = 4·seg
|
|
16
|
-
* 민 것(n 점) ExtrudeGeometry 캡 2·(n−2) + 측면 2·n = 4n − 4
|
|
17
|
-
* 속 판 것 ExtrudeGeometry+구멍 4·(n + m) m 은 안쪽 테의 점 수
|
|
18
|
-
*
|
|
19
|
-
* ## 라운드를 안 세다가 12 배를 놓쳤다
|
|
20
|
-
*
|
|
21
|
-
* 한동안 `rect` 를 라운드와 무관하게 12 로 셌다. 「베벨과 라운드는 세지 않는다」고
|
|
22
|
-
* 적어 두기까지 했다. three 로 실제로 만들어 세어 보면
|
|
23
|
-
*
|
|
24
|
-
* rect 각짐 12 cube 와 같다 — 민다고 비싸지지 않는다
|
|
25
|
-
* rect round=24 140 모서리마다 8 점으로 뽑으므로 테가 36 점이 된다
|
|
26
|
-
* 속 판 rect round=24 160 구멍은 +20 이다. 고리의 캡이 통짜 캡보다 싸다
|
|
27
|
-
*
|
|
28
|
-
* **비싼 것은 미는 것이 아니라 라운드다.** 그리고 라운드는 저작자가 무심코 넣는
|
|
29
|
-
* 값이라, 예산이 12 배 적게 세고 있으면 그 선택의 대가가 화면에 안 나타난다.
|
|
30
|
-
*
|
|
31
|
-
* 그리는 쪽이 테를 몇 점으로 뽑는지(`SEGMENT_PRESETS[0]`)와 **같은 수**를 쓴다.
|
|
32
|
-
* 다르면 재는 값과 그려지는 것이 갈린다.
|
|
33
|
-
*/
|
|
34
|
-
export declare function trianglesOf(part: FigurePart): number;
|
|
35
|
-
/** `sizing` 이 없으면 무엇으로 보나 — 비례 확대가 가장 예측 가능하다. */
|
|
36
|
-
/**
|
|
37
|
-
* 회전까지 반영한 부품의 축별 크기.
|
|
38
|
-
*
|
|
39
|
-
* 회전한 상자의 여덟 꼭짓점을 각 축에 내린 것 — 축에 맞춘 경계다. 회전 행렬은
|
|
40
|
-
* `Rx·Ry·Rz` 이고 three 의 기본 Euler 순서('XYZ')와 같다. 그리는 쪽이 같은 순서로
|
|
41
|
-
* 돌리므로 여기서만 다르면 답이 달라진다.
|
|
42
|
-
*/
|
|
43
|
-
export declare function rotatedExtentOf(part: {
|
|
44
|
-
transform: PartTransform;
|
|
45
|
-
}): Vec3;
|
|
46
|
-
/**
|
|
47
|
-
* `stretch` 일 때 늘어나는 축.
|
|
48
|
-
*
|
|
49
|
-
* 형식에 축을 적는 자리가 없다. 대신 **부품이 가장 길게 뻗은 축**으로 정한다. 문서가
|
|
50
|
-
* 든 예(프레임 · 벨트 · 레일)가 전부 "길어서 그 물건인 것"이라 이 규칙과 맞는다.
|
|
51
|
-
* 정육면체에 가까운 부품에는 뜻이 없는데, 그런 부품은 애초에 `stretch` 를 쓸 자리가 아니다.
|
|
52
|
-
*
|
|
53
|
-
* **회전을 반영해 측정한다.** 크기만 보면 x 로 길게 그린 레일을 y 로 90° 돌려 세워도 여전히
|
|
54
|
-
* x 라고 답한다. 그러면 레일이 길이가 아니라 두께 쪽으로 늘어난다.
|
|
55
|
-
*
|
|
56
|
-
* 두 축의 길이가 같으면 x → z → y 순으로 정한다. 순서를 정해 두지 않으면 같은 부품이
|
|
57
|
-
* 소비처마다 다른 축으로 늘어난다.
|
|
58
|
-
*
|
|
59
|
-
* **소비처가 저마다 계산하면 안 된다.** 3D 와 2D 톱뷰와 속성 편집기가 같은 답을 내야
|
|
60
|
-
* 하므로 여기 한 곳에서만 정한다.
|
|
61
|
-
*/
|
|
62
|
-
export declare function stretchAxisOf(part: {
|
|
63
|
-
transform: PartTransform;
|
|
64
|
-
}): Axis;
|
|
65
|
-
/**
|
|
66
|
-
* 원본 데이터를 청사진으로 컴파일한다.
|
|
67
|
-
*
|
|
68
|
-
* `errors` 가 있으면 던진다 — 세울 수 없는 것을 반쯤 세운 청사진으로 돌려주면
|
|
69
|
-
* 어디서 잘못됐는지 알 수 없다. `violations` 는 청사진에 담아 돌려준다. 정책 위반은
|
|
70
|
-
* 컴파일을 막지 않고 숫자로 보인다.
|
|
71
|
-
*/
|
|
72
|
-
export declare function compile(source: unknown): FigureBlueprint;
|
|
73
|
-
//# sourceMappingURL=blueprint.d.ts.map
|
package/dist/blueprint.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"blueprint.d.ts","sourceRoot":"","sources":["../src/blueprint.ts"],"names":[],"mappings":"AAuBA,OAAO,EAAY,KAAK,cAAc,EAAE,MAAM,eAAe,CAAA;AAM7D,OAAO,EAAE,aAAa,EAAE,aAAa,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,WAAW,CAAA;AACrF,OAAO,EAeL,KAAK,eAAe,EACpB,KAAK,UAAU,EAGf,KAAK,IAAI,EACT,KAAK,aAAa,EAClB,KAAK,IAAI,EACV,MAAM,YAAY,CAAA;AAEnB,+CAA+C;AAC/C,qBAAa,kBAAmB,SAAQ,KAAK;IAC3C,QAAQ,CAAC,MAAM,EAAE,cAAc,CAAC,QAAQ,CAAC,CAAA;gBAE7B,MAAM,EAAE,cAAc,CAAC,QAAQ,CAAC;CAS7C;AAED;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,UAAU,GAAG,MAAM,CA0BpD;AAuBD,kDAAkD;AAElD;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE;IAAE,SAAS,EAAE,aAAa,CAAA;CAAE,GAAG,IAAI,CAuBxE;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE;IAAE,SAAS,EAAE,aAAa,CAAA;CAAE,GAAG,IAAI,CAKtE;AAyFD;;;;;;GAMG;AACH,wBAAgB,OAAO,CAAC,MAAM,EAAE,OAAO,GAAG,eAAe,CAwHxD"}
|
package/dist/blueprint.js
DELETED
|
@@ -1,388 +0,0 @@
|
|
|
1
|
-
/*
|
|
2
|
-
* Copyright © HatioLab Inc. All rights reserved.
|
|
3
|
-
*
|
|
4
|
-
* 원본 데이터 → 청사진 컴파일.
|
|
5
|
-
*
|
|
6
|
-
* 원본 데이터는 편집을 위한 형식이다. 씬이 그것을 그대로 렌더링하면 부품마다 mesh 가 생겨서
|
|
7
|
-
* 자산 500 개 × 부품 8 개 = 4000 draw call 이 된다. 청사진은 그것을 줄인 형식이다.
|
|
8
|
-
*
|
|
9
|
-
* 핵심은 **병합**이다. 같은 재질·슬롯을 쓰고 애니메이션이 없는 부품을 한 묶음으로
|
|
10
|
-
* 묶는다. 3D 는 그 묶음의 geometry 를 합치고, 2D 는 윤곽을 한 path 로 합쳐 한 번에
|
|
11
|
-
* 채운다. 병목이 양쪽 다 묶음 수여서 같은 병합이 함께 값을 한다.
|
|
12
|
-
*
|
|
13
|
-
* 자산당 묶음 수 = 재질·슬롯 조합 수 + 애니메이션 포인트 수 + 크기 반응이 다른 부품 수
|
|
14
|
-
*
|
|
15
|
-
* **합칠 수 없는 부품이 둘 있다.**
|
|
16
|
-
*
|
|
17
|
-
* 애니메이션이 걸린 부품은 합치지 않는다. 합치면 그 부품만 따로 움직일 수 없다.
|
|
18
|
-
*
|
|
19
|
-
* `sizing` 이 `'scale'` 이 아닌 부품도 합치지 않는다. 이유가 같다 — 합친 geometry 는
|
|
20
|
-
* 변환을 하나만 받는데, `fixed` 는 크기를 그대로 두고 `stretch` 는 한 축만 늘리고
|
|
21
|
-
* `repeat` 는 개수를 바꾼다. 인스턴스마다 다르게 반응해야 하므로 각자 서야 한다.
|
|
22
|
-
*/
|
|
23
|
-
import { validate } from "./validate.js";
|
|
24
|
-
import { centredSource } from "./origin.js";
|
|
25
|
-
import { geometryKeyOf, materialKeyOf, usesSegments } from "./keys.js";
|
|
26
|
-
import { jointFrames, mergeKeyOf, movingNames, standsAlone } from "./grouping.js";
|
|
27
|
-
// 키는 keys.ts 가 기준이 되는 원본이다. 소비처가 쓰던 이름 그대로 다시 내보낸다.
|
|
28
|
-
export { geometryKeyOf, emissiveKeyOf, materialKeyOf, usesSegments } from "./keys.js";
|
|
29
|
-
import { BLUEPRINT_VERSION, DEFAULT_SIZING, FIGURE_SOURCE_VERSION, SEGMENT_PRESETS } from "./types.js";
|
|
30
|
-
/** 컴파일할 수 없을 때 던진다. 오류보고없이 빈 청사진을 돌려주지 않는다. */
|
|
31
|
-
export class FigureCompileError extends Error {
|
|
32
|
-
errors;
|
|
33
|
-
constructor(errors) {
|
|
34
|
-
const head = errors
|
|
35
|
-
.slice(0, 3)
|
|
36
|
-
.map(e => `${e.path || '(root)'}: ${e.message}`)
|
|
37
|
-
.join(' / ');
|
|
38
|
-
super(`정본을 컴파일할 수 없다 — ${errors.length}건. ${head}`);
|
|
39
|
-
this.name = 'FigureCompileError';
|
|
40
|
-
this.errors = errors;
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
/**
|
|
44
|
-
* 삼각형 수 추정.
|
|
45
|
-
*
|
|
46
|
-
* 근거는 things-scene 의 geometry 생성 인자다.
|
|
47
|
-
*
|
|
48
|
-
* cube · wall BoxGeometry 면 6 × 2 = 12
|
|
49
|
-
* cylinder CylinderGeometry(seg) 측면 2·seg + 캡 2·seg = 4·seg
|
|
50
|
-
* 민 것(n 점) ExtrudeGeometry 캡 2·(n−2) + 측면 2·n = 4n − 4
|
|
51
|
-
* 속 판 것 ExtrudeGeometry+구멍 4·(n + m) m 은 안쪽 테의 점 수
|
|
52
|
-
*
|
|
53
|
-
* ## 라운드를 안 세다가 12 배를 놓쳤다
|
|
54
|
-
*
|
|
55
|
-
* 한동안 `rect` 를 라운드와 무관하게 12 로 셌다. 「베벨과 라운드는 세지 않는다」고
|
|
56
|
-
* 적어 두기까지 했다. three 로 실제로 만들어 세어 보면
|
|
57
|
-
*
|
|
58
|
-
* rect 각짐 12 cube 와 같다 — 민다고 비싸지지 않는다
|
|
59
|
-
* rect round=24 140 모서리마다 8 점으로 뽑으므로 테가 36 점이 된다
|
|
60
|
-
* 속 판 rect round=24 160 구멍은 +20 이다. 고리의 캡이 통짜 캡보다 싸다
|
|
61
|
-
*
|
|
62
|
-
* **비싼 것은 미는 것이 아니라 라운드다.** 그리고 라운드는 저작자가 무심코 넣는
|
|
63
|
-
* 값이라, 예산이 12 배 적게 세고 있으면 그 선택의 대가가 화면에 안 나타난다.
|
|
64
|
-
*
|
|
65
|
-
* 그리는 쪽이 테를 몇 점으로 뽑는지(`SEGMENT_PRESETS[0]`)와 **같은 수**를 쓴다.
|
|
66
|
-
* 다르면 재는 값과 그려지는 것이 갈린다.
|
|
67
|
-
*/
|
|
68
|
-
export function trianglesOf(part) {
|
|
69
|
-
const seg = part.segments ?? 12;
|
|
70
|
-
switch (part.primitive) {
|
|
71
|
-
case 'cube':
|
|
72
|
-
case 'wall':
|
|
73
|
-
return 12;
|
|
74
|
-
case 'cylinder':
|
|
75
|
-
return 4 * seg;
|
|
76
|
-
case 'sphere': {
|
|
77
|
-
const h = Math.max(2, Math.round(seg / 2));
|
|
78
|
-
return 2 * seg * (h - 1);
|
|
79
|
-
}
|
|
80
|
-
case 'rect':
|
|
81
|
-
case 'polygon': {
|
|
82
|
-
const n = outlinePointsOf(part);
|
|
83
|
-
const hollow = part.shape?.hollow;
|
|
84
|
-
if (!hollow)
|
|
85
|
-
return 4 * n - 4;
|
|
86
|
-
const m = innerPointsOf(part);
|
|
87
|
-
const ring = 4 * (n + m);
|
|
88
|
-
// 바닥이 0 이면 위아래가 다 뚫린 테두리다 — 덮는 판이 없다.
|
|
89
|
-
const floor = (hollow.floor ?? hollow.wall) > 0 ? 4 * n - 4 : 0;
|
|
90
|
-
return ring + floor;
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
/**
|
|
95
|
-
* 민 단면의 테가 몇 점인가.
|
|
96
|
-
*
|
|
97
|
-
* 라운드가 있으면 모서리 넷이 저마다 곡선이 되고, 그리는 쪽이 곡선 하나를
|
|
98
|
-
* `SEGMENT_PRESETS[0]` 점으로 뽑는다. 곡선 사이를 잇는 직선의 끝점 넷이 더 붙는다.
|
|
99
|
-
*
|
|
100
|
-
* `polygon` 은 라운드를 쓰지 않는다 — 그리는 쪽이 적힌 점을 그대로 잇는다.
|
|
101
|
-
*/
|
|
102
|
-
function outlinePointsOf(part) {
|
|
103
|
-
if (part.primitive === 'polygon')
|
|
104
|
-
return part.shape?.path?.length ?? 3;
|
|
105
|
-
return part.shape?.round ? 4 * SEGMENT_PRESETS[0] + 4 : 4;
|
|
106
|
-
}
|
|
107
|
-
/** 안쪽 테. 벽 두께만큼 들어오므로 라운드가 그만큼 줄고, 0 이 되면 각진 모서리가 된다. */
|
|
108
|
-
function innerPointsOf(part) {
|
|
109
|
-
if (part.primitive === 'polygon')
|
|
110
|
-
return part.shape?.path?.length ?? 3;
|
|
111
|
-
const round = (part.shape?.round ?? 0) - (part.shape?.hollow?.wall ?? 0);
|
|
112
|
-
return round > 0 ? 4 * SEGMENT_PRESETS[0] + 4 : 4;
|
|
113
|
-
}
|
|
114
|
-
/** `sizing` 이 없으면 무엇으로 보나 — 비례 확대가 가장 예측 가능하다. */
|
|
115
|
-
/**
|
|
116
|
-
* 회전까지 반영한 부품의 축별 크기.
|
|
117
|
-
*
|
|
118
|
-
* 회전한 상자의 여덟 꼭짓점을 각 축에 내린 것 — 축에 맞춘 경계다. 회전 행렬은
|
|
119
|
-
* `Rx·Ry·Rz` 이고 three 의 기본 Euler 순서('XYZ')와 같다. 그리는 쪽이 같은 순서로
|
|
120
|
-
* 돌리므로 여기서만 다르면 답이 달라진다.
|
|
121
|
-
*/
|
|
122
|
-
export function rotatedExtentOf(part) {
|
|
123
|
-
const { size, rotation } = part.transform;
|
|
124
|
-
if (!rotation)
|
|
125
|
-
return { ...size };
|
|
126
|
-
const rad = Math.PI / 180;
|
|
127
|
-
const cx = Math.cos((rotation.x ?? 0) * rad);
|
|
128
|
-
const sx = Math.sin((rotation.x ?? 0) * rad);
|
|
129
|
-
const cy = Math.cos((rotation.y ?? 0) * rad);
|
|
130
|
-
const sy = Math.sin((rotation.y ?? 0) * rad);
|
|
131
|
-
const cz = Math.cos((rotation.z ?? 0) * rad);
|
|
132
|
-
const sz = Math.sin((rotation.z ?? 0) * rad);
|
|
133
|
-
// Rx·Ry·Rz 의 세 줄
|
|
134
|
-
const r = [
|
|
135
|
-
[cy * cz, -cy * sz, sy],
|
|
136
|
-
[sx * sy * cz + cx * sz, -sx * sy * sz + cx * cz, -sx * cy],
|
|
137
|
-
[-cx * sy * cz + sx * sz, cx * sy * sz + sx * cz, cx * cy]
|
|
138
|
-
];
|
|
139
|
-
const along = (row) => Math.abs(row[0]) * size.x + Math.abs(row[1]) * size.y + Math.abs(row[2]) * size.z;
|
|
140
|
-
return { x: along(r[0]), y: along(r[1]), z: along(r[2]) };
|
|
141
|
-
}
|
|
142
|
-
/**
|
|
143
|
-
* `stretch` 일 때 늘어나는 축.
|
|
144
|
-
*
|
|
145
|
-
* 형식에 축을 적는 자리가 없다. 대신 **부품이 가장 길게 뻗은 축**으로 정한다. 문서가
|
|
146
|
-
* 든 예(프레임 · 벨트 · 레일)가 전부 "길어서 그 물건인 것"이라 이 규칙과 맞는다.
|
|
147
|
-
* 정육면체에 가까운 부품에는 뜻이 없는데, 그런 부품은 애초에 `stretch` 를 쓸 자리가 아니다.
|
|
148
|
-
*
|
|
149
|
-
* **회전을 반영해 측정한다.** 크기만 보면 x 로 길게 그린 레일을 y 로 90° 돌려 세워도 여전히
|
|
150
|
-
* x 라고 답한다. 그러면 레일이 길이가 아니라 두께 쪽으로 늘어난다.
|
|
151
|
-
*
|
|
152
|
-
* 두 축의 길이가 같으면 x → z → y 순으로 정한다. 순서를 정해 두지 않으면 같은 부품이
|
|
153
|
-
* 소비처마다 다른 축으로 늘어난다.
|
|
154
|
-
*
|
|
155
|
-
* **소비처가 저마다 계산하면 안 된다.** 3D 와 2D 톱뷰와 속성 편집기가 같은 답을 내야
|
|
156
|
-
* 하므로 여기 한 곳에서만 정한다.
|
|
157
|
-
*/
|
|
158
|
-
export function stretchAxisOf(part) {
|
|
159
|
-
const { x, y, z } = rotatedExtentOf(part);
|
|
160
|
-
if (x >= z && x >= y)
|
|
161
|
-
return 'x';
|
|
162
|
-
if (z >= y)
|
|
163
|
-
return 'z';
|
|
164
|
-
return 'y';
|
|
165
|
-
}
|
|
166
|
-
/**
|
|
167
|
-
* 능력의 닻 — 그리지 않는 자리를 청사진으로 옮긴다.
|
|
168
|
-
*
|
|
169
|
-
* 기하를 안 만든다(`geometryKey`·`triangles` 없음). 자리 계산에 필요한 넷만 실어 나른다.
|
|
170
|
-
*
|
|
171
|
-
* 이름을 `anchorOf` 로 두지 않는다 — 그 이름은 `sizing.ts` 에서 「어느 **면**을 붙잡나」를 뜻한다.
|
|
172
|
-
* 한 형식 안에서 같은 이름이 두 가지를 뜻하면 읽는 사람이 매번 어느 쪽인지 가려야 한다.
|
|
173
|
-
*/
|
|
174
|
-
function capabilityAnchorOf(part) {
|
|
175
|
-
const spec = part.capability;
|
|
176
|
-
/* The part is already centred, so the anchor carries the brand it came with. */
|
|
177
|
-
const at = {
|
|
178
|
-
name: part.name,
|
|
179
|
-
roles: [...spec.roles],
|
|
180
|
-
transform: part.transform,
|
|
181
|
-
sizing: part.sizing ?? DEFAULT_SIZING
|
|
182
|
-
};
|
|
183
|
-
if (part.anchor !== undefined)
|
|
184
|
-
at.anchor = part.anchor;
|
|
185
|
-
if (part.repeat !== undefined)
|
|
186
|
-
at.repeat = part.repeat;
|
|
187
|
-
if (spec.accepts !== undefined)
|
|
188
|
-
at.accepts = spec.accepts;
|
|
189
|
-
if (spec.capacity !== undefined)
|
|
190
|
-
at.capacity = spec.capacity;
|
|
191
|
-
if (spec.direction !== undefined)
|
|
192
|
-
at.direction = spec.direction;
|
|
193
|
-
return at;
|
|
194
|
-
}
|
|
195
|
-
function memberOf(part) {
|
|
196
|
-
/* The part is already centred, so the member carries the brand it came with. */
|
|
197
|
-
const member = {
|
|
198
|
-
name: part.name,
|
|
199
|
-
primitive: part.primitive,
|
|
200
|
-
geometryKey: geometryKeyOf(part),
|
|
201
|
-
transform: part.transform,
|
|
202
|
-
sizing: part.sizing ?? DEFAULT_SIZING,
|
|
203
|
-
triangles: trianglesOf(part)
|
|
204
|
-
};
|
|
205
|
-
if (usesSegments(part.primitive) && part.segments !== undefined)
|
|
206
|
-
member.segments = part.segments;
|
|
207
|
-
if (part.keepRound !== undefined)
|
|
208
|
-
member.keepRound = part.keepRound;
|
|
209
|
-
if (part.anchor !== undefined)
|
|
210
|
-
member.anchor = part.anchor;
|
|
211
|
-
if (part.repeat !== undefined)
|
|
212
|
-
member.repeat = part.repeat;
|
|
213
|
-
if (part.shape !== undefined)
|
|
214
|
-
member.shape = part.shape;
|
|
215
|
-
return member;
|
|
216
|
-
}
|
|
217
|
-
/**
|
|
218
|
-
* Joints as nodes, parents before children (ADR-0066).
|
|
219
|
-
*
|
|
220
|
-
* A joint's parent node is the frame its child's parent part moves in, and `attach` names that part so
|
|
221
|
-
* the runtime can move the origin with it under sizing. The axis is made unit length here, once, so every
|
|
222
|
-
* consumer turns by the same angle per degree.
|
|
223
|
-
*/
|
|
224
|
-
function jointsOf(src, frames) {
|
|
225
|
-
const parentOf = new Map(src.parts.filter(part => part.parent !== undefined).map(part => [part.name, part.parent]));
|
|
226
|
-
const nodes = (src.joints ?? []).map(joint => {
|
|
227
|
-
const length = Math.hypot(joint.axis.x, joint.axis.y, joint.axis.z);
|
|
228
|
-
const node = {
|
|
229
|
-
name: joint.name,
|
|
230
|
-
type: joint.type,
|
|
231
|
-
child: joint.child,
|
|
232
|
-
origin: { ...joint.origin },
|
|
233
|
-
axis: { x: joint.axis.x / length, y: joint.axis.y / length, z: joint.axis.z / length }
|
|
234
|
-
};
|
|
235
|
-
if (joint.limits !== undefined)
|
|
236
|
-
node.limits = { min: joint.limits.min, max: joint.limits.max };
|
|
237
|
-
const attach = parentOf.get(joint.child);
|
|
238
|
-
if (attach !== undefined) {
|
|
239
|
-
node.attach = attach;
|
|
240
|
-
const parent = frames.get(attach);
|
|
241
|
-
if (parent !== undefined)
|
|
242
|
-
node.parent = parent;
|
|
243
|
-
}
|
|
244
|
-
return node;
|
|
245
|
-
});
|
|
246
|
-
// Parents first: a node can be built only once the node it sits in exists.
|
|
247
|
-
const ordered = [];
|
|
248
|
-
const placed = new Set();
|
|
249
|
-
let pending = nodes;
|
|
250
|
-
while (pending.length > 0) {
|
|
251
|
-
const ready = pending.filter(node => node.parent === undefined || placed.has(node.parent));
|
|
252
|
-
// validate refuses cycles, so every pass places at least one node
|
|
253
|
-
for (const node of ready) {
|
|
254
|
-
ordered.push(node);
|
|
255
|
-
placed.add(node.name);
|
|
256
|
-
}
|
|
257
|
-
pending = pending.filter(node => !placed.has(node.name));
|
|
258
|
-
}
|
|
259
|
-
return ordered;
|
|
260
|
-
}
|
|
261
|
-
/**
|
|
262
|
-
* 원본 데이터를 청사진으로 컴파일한다.
|
|
263
|
-
*
|
|
264
|
-
* `errors` 가 있으면 던진다 — 세울 수 없는 것을 반쯤 세운 청사진으로 돌려주면
|
|
265
|
-
* 어디서 잘못됐는지 알 수 없다. `violations` 는 청사진에 담아 돌려준다. 정책 위반은
|
|
266
|
-
* 컴파일을 막지 않고 숫자로 보인다.
|
|
267
|
-
*/
|
|
268
|
-
export function compile(source) {
|
|
269
|
-
const { errors, violations } = validate(source);
|
|
270
|
-
if (errors.length > 0)
|
|
271
|
-
throw new FigureCompileError(errors);
|
|
272
|
-
/* Everything below reads box-centred coordinates, as the blueprint and the runtime do (origin.ts). */
|
|
273
|
-
const src = centredSource(source);
|
|
274
|
-
const groups = [];
|
|
275
|
-
const animations = src.animations ?? [];
|
|
276
|
-
const parameters = src.parameters ?? [];
|
|
277
|
-
/*
|
|
278
|
-
어느 부품이 **따로 변환되나.** 묶음을 가르는 판단이 이걸 먼저 알아야 한다.
|
|
279
|
-
|
|
280
|
-
파라미터가 모는 부품도 같이 센다 — 값이 몰든 시각이 몰든 **따로 변환되는 부품은 따로
|
|
281
|
-
그린다.** 묶음 수는 구동 방식과 무관하다.
|
|
282
|
-
*/
|
|
283
|
-
const moving = movingNames({ animations, parameters });
|
|
284
|
-
/* Which joint frame each part moves in. Parts merge only within one frame (ADR-0066 decision 4). */
|
|
285
|
-
const frames = jointFrames(src);
|
|
286
|
-
const labels = [];
|
|
287
|
-
const anchors = [];
|
|
288
|
-
const byKey = new Map();
|
|
289
|
-
for (const part of src.parts) {
|
|
290
|
-
if (part.label !== undefined) {
|
|
291
|
-
labels.push({ ...part.label, at: part.name });
|
|
292
|
-
}
|
|
293
|
-
/*
|
|
294
|
-
능력의 닻은 **그리는 목록에 넣지 않는다.** 그리지 않고 세지도 않는다 — `costOf` 가 보는 것이
|
|
295
|
-
`groups` 이므로, 여기서 가르면 자리가 삼각형·묶음·부품 수에 끼어들 길이 없다.
|
|
296
|
-
*/
|
|
297
|
-
const frame = frames.get(part.name);
|
|
298
|
-
if (part.capability !== undefined) {
|
|
299
|
-
const anchor = capabilityAnchorOf(part);
|
|
300
|
-
if (frame !== undefined)
|
|
301
|
-
anchor.joint = frame;
|
|
302
|
-
anchors.push(anchor);
|
|
303
|
-
continue;
|
|
304
|
-
}
|
|
305
|
-
if (moving.has(part.name)) {
|
|
306
|
-
// clip 이 움직이는 부품은 단독 묶음이다 — 합치면 따로 움직일 수 없다
|
|
307
|
-
const group = {
|
|
308
|
-
materialKey: materialKeyOf(part),
|
|
309
|
-
material: part.material,
|
|
310
|
-
animated: true,
|
|
311
|
-
members: [memberOf(part)]
|
|
312
|
-
};
|
|
313
|
-
if (part.materialSlot !== undefined)
|
|
314
|
-
group.materialSlot = part.materialSlot;
|
|
315
|
-
if (frame !== undefined)
|
|
316
|
-
group.joint = frame;
|
|
317
|
-
groups.push(group);
|
|
318
|
-
continue;
|
|
319
|
-
}
|
|
320
|
-
if (standsAlone(part, moving)) {
|
|
321
|
-
// 크기 반응이 다른 부품도 단독 묶음이다 — 합친 geometry 는 변환을 하나만 받는다
|
|
322
|
-
const group = {
|
|
323
|
-
materialKey: materialKeyOf(part),
|
|
324
|
-
material: part.material,
|
|
325
|
-
animated: false,
|
|
326
|
-
members: [memberOf(part)]
|
|
327
|
-
};
|
|
328
|
-
if (part.materialSlot !== undefined)
|
|
329
|
-
group.materialSlot = part.materialSlot;
|
|
330
|
-
if (frame !== undefined)
|
|
331
|
-
group.joint = frame;
|
|
332
|
-
groups.push(group);
|
|
333
|
-
continue;
|
|
334
|
-
}
|
|
335
|
-
const key = mergeKeyOf(part, frames);
|
|
336
|
-
const existing = byKey.get(key);
|
|
337
|
-
if (existing) {
|
|
338
|
-
existing.members.push(memberOf(part));
|
|
339
|
-
continue;
|
|
340
|
-
}
|
|
341
|
-
const group = {
|
|
342
|
-
materialKey: materialKeyOf(part),
|
|
343
|
-
material: part.material,
|
|
344
|
-
animated: false,
|
|
345
|
-
members: [memberOf(part)]
|
|
346
|
-
};
|
|
347
|
-
if (part.materialSlot !== undefined)
|
|
348
|
-
group.materialSlot = part.materialSlot;
|
|
349
|
-
if (frame !== undefined)
|
|
350
|
-
group.joint = frame;
|
|
351
|
-
byKey.set(key, group);
|
|
352
|
-
groups.push(group);
|
|
353
|
-
}
|
|
354
|
-
const triangles = groups.reduce((sum, g) => sum + g.members.reduce((s, m) => s + m.triangles, 0), 0);
|
|
355
|
-
const blueprint = {
|
|
356
|
-
version: BLUEPRINT_VERSION,
|
|
357
|
-
/*
|
|
358
|
-
The source edition travels with the blueprint. A consumer never sees the source — it asks
|
|
359
|
-
the service for a compiled blueprint — so without this it cannot tell which edition of the
|
|
360
|
-
format it is holding, which is the whole reason `FigureSource.version` exists.
|
|
361
|
-
|
|
362
|
-
validate has already refused any other edition, including a missing one.
|
|
363
|
-
*/
|
|
364
|
-
sourceVersion: FIGURE_SOURCE_VERSION,
|
|
365
|
-
type: src.type,
|
|
366
|
-
base: src.base,
|
|
367
|
-
budget: { triangles, groups: groups.length },
|
|
368
|
-
groups,
|
|
369
|
-
anchors,
|
|
370
|
-
animations,
|
|
371
|
-
parameters,
|
|
372
|
-
labels,
|
|
373
|
-
/* 정본이 선언한 능력을 그대로 실어 나른다 — 판정은 씬이 한다. */
|
|
374
|
-
capabilities: src.capabilities ?? [],
|
|
375
|
-
violations
|
|
376
|
-
};
|
|
377
|
-
// 등급을 실어 보낸다 — 부품 수 한도가 여기서 나오므로, 없으면 소비처가 예산을
|
|
378
|
-
// 판단할 수 없다.
|
|
379
|
-
if (src.detailLevel !== undefined)
|
|
380
|
-
blueprint.detailLevel = src.detailLevel;
|
|
381
|
-
if (src.placement !== undefined)
|
|
382
|
-
blueprint.placement = src.placement;
|
|
383
|
-
// Carried only when the source declares joints, so blueprints without them keep their exact shape.
|
|
384
|
-
if (src.joints !== undefined && src.joints.length > 0)
|
|
385
|
-
blueprint.joints = jointsOf(src, frames);
|
|
386
|
-
return blueprint;
|
|
387
|
-
}
|
|
388
|
-
//# sourceMappingURL=blueprint.js.map
|