@hatiolab/figure-model 0.1.12 → 0.1.13
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/dist/gate.d.ts +36 -0
- package/dist/gate.d.ts.map +1 -0
- package/dist/gate.js +123 -0
- package/dist/gate.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +7 -0
- package/dist/index.js.map +1 -1
- package/dist/sizing.d.ts +179 -0
- package/dist/sizing.d.ts.map +1 -0
- package/dist/sizing.js +475 -0
- package/dist/sizing.js.map +1 -0
- package/package.json +1 -1
package/dist/gate.d.ts
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import type { Axis, FigureBlueprint, FigureSource } from './types.ts';
|
|
2
|
+
/** 크기를 바꿔 보는 일곱 가지. 축 하나씩 셋, 둘씩 셋, 셋 한꺼번에. */
|
|
3
|
+
export declare const SIZING_WAYS: readonly {
|
|
4
|
+
readonly name: string;
|
|
5
|
+
readonly axes: readonly Axis[];
|
|
6
|
+
}[];
|
|
7
|
+
export interface SizingFinding {
|
|
8
|
+
/**
|
|
9
|
+
* `sizing-splits` 이 조합에서 조각이 갈라진다 — 발행을 막는다
|
|
10
|
+
* `sizing-loose` 1배에서 이미 여러 조각이다 — 알리기만 한다
|
|
11
|
+
*/
|
|
12
|
+
code: 'sizing-splits' | 'sizing-loose';
|
|
13
|
+
/** 어느 조합에서. `sizing-loose` 에는 없다. */
|
|
14
|
+
way?: string;
|
|
15
|
+
message: string;
|
|
16
|
+
/** 갈라져 나온 조각들의 부품 이름. 숫자가 아니라 자리를 말한다. */
|
|
17
|
+
clumps: string[][];
|
|
18
|
+
}
|
|
19
|
+
export interface SizingReport {
|
|
20
|
+
findings: SizingFinding[];
|
|
21
|
+
/** 1배에서의 덩어리 수. 1 이면 붙어 있는 한 덩어리다. */
|
|
22
|
+
clumpsAtOne: number;
|
|
23
|
+
/** 몇 배로 재봤나. */
|
|
24
|
+
factor: number;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* 크기를 바꿔 봐도 한 덩어리인가.
|
|
28
|
+
*
|
|
29
|
+
* 1배에서 이미 갈라져 있으면 그것을 먼저 말하고(`sizing-loose`), 그 뒤 일곱 조합에서 **덩어리가
|
|
30
|
+
* 늘어나는** 경우를 찾는다. 늘어나지 않으면 조용하다 — 부품이 움직였는지가 아니라 **떨어졌는지**를
|
|
31
|
+
* 보기 때문이다.
|
|
32
|
+
*/
|
|
33
|
+
export declare function sizingReport(blueprint: FigureBlueprint, factor?: number): SizingReport;
|
|
34
|
+
/** 정본 문자열이 아니라 객체를 받는 쪽. 부르는 자리가 이미 컴파일해 두었으면 위 함수를 쓴다. */
|
|
35
|
+
export declare function sizingReportOf(source: FigureSource, factor?: number): SizingReport;
|
|
36
|
+
//# sourceMappingURL=gate.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gate.d.ts","sourceRoot":"","sources":["../src/gate.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,IAAI,EAAmB,eAAe,EAAE,YAAY,EAAQ,MAAM,YAAY,CAAA;AAqB5F,8CAA8C;AAC9C,eAAO,MAAM,WAAW,EAAE,SAAS;IAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,SAAS,IAAI,EAAE,CAAA;CAAE,EAQ3F,CAAA;AAkED,MAAM,WAAW,aAAa;IAC5B;;;OAGG;IACH,IAAI,EAAE,eAAe,GAAG,cAAc,CAAA;IACtC,qCAAqC;IACrC,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,OAAO,EAAE,MAAM,CAAA;IACf,0CAA0C;IAC1C,MAAM,EAAE,MAAM,EAAE,EAAE,CAAA;CACnB;AAED,MAAM,WAAW,YAAY;IAC3B,QAAQ,EAAE,aAAa,EAAE,CAAA;IACzB,sCAAsC;IACtC,WAAW,EAAE,MAAM,CAAA;IACnB,gBAAgB;IAChB,MAAM,EAAE,MAAM,CAAA;CACf;AAED;;;;;;GAMG;AACH,wBAAgB,YAAY,CAAC,SAAS,EAAE,eAAe,EAAE,MAAM,GAAE,MAAe,GAAG,YAAY,CAkC9F;AAED,2DAA2D;AAC3D,wBAAgB,cAAc,CAAC,MAAM,EAAE,YAAY,EAAE,MAAM,GAAE,MAAe,GAAG,YAAY,CAE1F"}
|
package/dist/gate.js
ADDED
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
import { compile } from "./blueprint.js";
|
|
2
|
+
import { rotatedExtentOf } from "./blueprint.js";
|
|
3
|
+
import { anchorOf, sizingPosition, sizingScale } from "./sizing.js";
|
|
4
|
+
/*
|
|
5
|
+
* 발행해도 되나 — **크기를 바꿔 봐야 알 수 있는 것들.**
|
|
6
|
+
*
|
|
7
|
+
* ## 왜 형식이 이것을 재나
|
|
8
|
+
*
|
|
9
|
+
* 이 검사는 브라우저 하네스에만 있었다(things-factory `test/browser/check-figure-scaling.mjs`). 그
|
|
10
|
+
* 자리에서는 사람이 돌릴 때만 돌고, 서버는 같은 질문에 답할 방법이 없어 **아무 검사 없이 발행이
|
|
11
|
+
* 되었다.** 앵커의 뜻을 아는 것이 형식이므로(`sizing.ts`), 그 뜻이 실제로 성립하는지도 형식이 잰다.
|
|
12
|
+
*
|
|
13
|
+
* ## 무엇을 재나
|
|
14
|
+
*
|
|
15
|
+
* **덩어리가 늘어나지 않는가.** 도형은 서로 닿아 한 덩어리여야 한다. 크기를 바꿨을 때 조각이 갈라
|
|
16
|
+
* 지면 사람 눈에 「부서졌다」로 보인다 — 시그널타워를 3배로 세우니 램프가 기둥 위 공중에 뜬 것이
|
|
17
|
+
* 그것이었고, 앵커 규칙이 생긴 이유다.
|
|
18
|
+
*
|
|
19
|
+
* 축을 하나씩만 늘리는 것으로는 부족하다. x 만 늘려서 멀쩡한 것이 x·z 를 함께 늘리면 갈라진다 —
|
|
20
|
+
* `aspect-` 처럼 다른 축을 보는 규칙이 있어서다. 그래서 **일곱 조합**을 전부 본다.
|
|
21
|
+
*/
|
|
22
|
+
/** 크기를 바꿔 보는 일곱 가지. 축 하나씩 셋, 둘씩 셋, 셋 한꺼번에. */
|
|
23
|
+
export const SIZING_WAYS = [
|
|
24
|
+
{ name: 'x', axes: ['x'] },
|
|
25
|
+
{ name: 'y', axes: ['y'] },
|
|
26
|
+
{ name: 'z', axes: ['z'] },
|
|
27
|
+
{ name: 'x-y', axes: ['x', 'y'] },
|
|
28
|
+
{ name: 'x-z', axes: ['x', 'z'] },
|
|
29
|
+
{ name: 'y-z', axes: ['y', 'z'] },
|
|
30
|
+
{ name: 'x-y-z', axes: ['x', 'y', 'z'] }
|
|
31
|
+
];
|
|
32
|
+
/** 몇 배로 재나. 2배면 대개 드러나고, 3배는 같은 자리를 더 크게 벌린다. */
|
|
33
|
+
const FACTOR = 2;
|
|
34
|
+
/**
|
|
35
|
+
* 맞대어 놓은 면은 정확히 0 만큼 떨어져 있다. 부동소수 나머지를 「닿았다」로 친다.
|
|
36
|
+
*
|
|
37
|
+
* 이 값을 키우면 실제로 떨어진 것도 붙은 것으로 읽히고, 줄이면 맞댄 면이 갈라진 것으로 읽힌다.
|
|
38
|
+
*/
|
|
39
|
+
const SKIN = 0.5;
|
|
40
|
+
const AXES = ['x', 'y', 'z'];
|
|
41
|
+
/** 이 배율에서 부품들이 차지하는 구간. */
|
|
42
|
+
function spansAt(members, base, scale) {
|
|
43
|
+
return members.map(member => {
|
|
44
|
+
/*
|
|
45
|
+
**배율을 한 번만 준다.** 축마다 따로 주면 `aspect-` 처럼 다른 축을 보는 규칙이 자기 축만 늘어난
|
|
46
|
+
세상을 보게 되어, 실제로 그려지는 것과 다른 답이 나온다.
|
|
47
|
+
*/
|
|
48
|
+
const at = sizingPosition(member, scale, base);
|
|
49
|
+
const sized = sizingScale(member, scale, base);
|
|
50
|
+
const extent = rotatedExtentOf(member);
|
|
51
|
+
const box = {};
|
|
52
|
+
for (const axis of AXES) {
|
|
53
|
+
const centre = at[axis] * scale[axis];
|
|
54
|
+
const half = (extent[axis] * sized[axis] * scale[axis]) / 2;
|
|
55
|
+
box[axis] = [centre - half, centre + half];
|
|
56
|
+
}
|
|
57
|
+
return { name: member.name, box };
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
function meets(a, b) {
|
|
61
|
+
return AXES.every(axis => a.box[axis][0] - SKIN <= b.box[axis][1] && b.box[axis][0] - SKIN <= a.box[axis][1]);
|
|
62
|
+
}
|
|
63
|
+
/** 닿는 것끼리 이어 덩어리를 만든다. 덩어리마다 부품 이름을 담는다. */
|
|
64
|
+
function clumpsOf(spans) {
|
|
65
|
+
const owner = spans.map((_, at) => at);
|
|
66
|
+
const rootOf = (at) => (owner[at] === at ? at : (owner[at] = rootOf(owner[at])));
|
|
67
|
+
for (let i = 0; i < spans.length; i++) {
|
|
68
|
+
for (let j = i + 1; j < spans.length; j++) {
|
|
69
|
+
if (meets(spans[i], spans[j]))
|
|
70
|
+
owner[rootOf(i)] = rootOf(j);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
const by = new Map();
|
|
74
|
+
spans.forEach((span, at) => {
|
|
75
|
+
const key = rootOf(at);
|
|
76
|
+
if (!by.has(key))
|
|
77
|
+
by.set(key, []);
|
|
78
|
+
by.get(key).push(span.name);
|
|
79
|
+
});
|
|
80
|
+
return [...by.values()];
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* 크기를 바꿔 봐도 한 덩어리인가.
|
|
84
|
+
*
|
|
85
|
+
* 1배에서 이미 갈라져 있으면 그것을 먼저 말하고(`sizing-loose`), 그 뒤 일곱 조합에서 **덩어리가
|
|
86
|
+
* 늘어나는** 경우를 찾는다. 늘어나지 않으면 조용하다 — 부품이 움직였는지가 아니라 **떨어졌는지**를
|
|
87
|
+
* 보기 때문이다.
|
|
88
|
+
*/
|
|
89
|
+
export function sizingReport(blueprint, factor = FACTOR) {
|
|
90
|
+
const members = blueprint.groups.flatMap((group) => group.members);
|
|
91
|
+
const findings = [];
|
|
92
|
+
if (!members.length) {
|
|
93
|
+
return { findings, clumpsAtOne: 0, factor };
|
|
94
|
+
}
|
|
95
|
+
const one = clumpsOf(spansAt(members, blueprint.base, { x: 1, y: 1, z: 1 }));
|
|
96
|
+
if (one.length > 1) {
|
|
97
|
+
findings.push({
|
|
98
|
+
code: 'sizing-loose',
|
|
99
|
+
message: `1배에서 이미 ${one.length} 조각이다. 크기를 바꾸기 전에 이미 떨어져 있다`,
|
|
100
|
+
clumps: one
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
for (const way of SIZING_WAYS) {
|
|
104
|
+
const scale = { x: 1, y: 1, z: 1 };
|
|
105
|
+
for (const axis of way.axes)
|
|
106
|
+
scale[axis] = factor;
|
|
107
|
+
const grown = clumpsOf(spansAt(members, blueprint.base, scale));
|
|
108
|
+
if (grown.length > one.length) {
|
|
109
|
+
findings.push({
|
|
110
|
+
code: 'sizing-splits',
|
|
111
|
+
way: way.name,
|
|
112
|
+
message: `${way.name} 축을 ${factor}배로 하면 ${one.length} 조각이 ${grown.length} 조각으로 갈라진다`,
|
|
113
|
+
clumps: grown
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
return { findings, clumpsAtOne: one.length, factor };
|
|
118
|
+
}
|
|
119
|
+
/** 정본 문자열이 아니라 객체를 받는 쪽. 부르는 자리가 이미 컴파일해 두었으면 위 함수를 쓴다. */
|
|
120
|
+
export function sizingReportOf(source, factor = FACTOR) {
|
|
121
|
+
return sizingReport(compile(source), factor);
|
|
122
|
+
}
|
|
123
|
+
//# sourceMappingURL=gate.js.map
|
package/dist/gate.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gate.js","sourceRoot":"","sources":["../src/gate.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -4,4 +4,6 @@ export { compile, FigureCompileError, geometryKeyOf, materialKeyOf, rotatedExten
|
|
|
4
4
|
export { costOf, describeCost, scoreOf, type FigureBudgetUse, type FigureCost, type FigureCostAt, type FigureGrade, type FigureScore } from './cost.ts';
|
|
5
5
|
export { costCurve, costCurveSvg, type CostCurveOptions, type CostCurvePoint } from './cost-chart.ts';
|
|
6
6
|
export { blueprintProblems } from './blueprint-shape.ts';
|
|
7
|
+
export { anchorOf, needsOwnMesh, repeatOffset, repeatPlan, REPEAT_LIMIT, rotatedExtent, sizingPosition, sizingScale, stretchAxis, type Axis as SizingAxis, type InstanceScale } from './sizing.ts';
|
|
8
|
+
export { sizingReport, sizingReportOf, SIZING_WAYS, type SizingFinding, type SizingReport } from './gate.ts';
|
|
7
9
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAYA,cAAc,YAAY,CAAA;AAC1B,OAAO,EAAE,QAAQ,EAAE,KAAK,cAAc,EAAE,MAAM,eAAe,CAAA;AAC7D,OAAO,EACL,OAAO,EACP,kBAAkB,EAClB,aAAa,EACb,aAAa,EACb,eAAe,EACf,aAAa,EACb,WAAW,EACX,YAAY,EACb,MAAM,gBAAgB,CAAA;AACvB,OAAO,EACL,MAAM,EACN,YAAY,EACZ,OAAO,EACP,KAAK,eAAe,EACpB,KAAK,UAAU,EACf,KAAK,YAAY,EACjB,KAAK,WAAW,EAChB,KAAK,WAAW,EACjB,MAAM,WAAW,CAAA;AAClB,OAAO,EAAE,SAAS,EAAE,YAAY,EAAE,KAAK,gBAAgB,EAAE,KAAK,cAAc,EAAE,MAAM,iBAAiB,CAAA;AAErG,OAAO,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAA"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAYA,cAAc,YAAY,CAAA;AAC1B,OAAO,EAAE,QAAQ,EAAE,KAAK,cAAc,EAAE,MAAM,eAAe,CAAA;AAC7D,OAAO,EACL,OAAO,EACP,kBAAkB,EAClB,aAAa,EACb,aAAa,EACb,eAAe,EACf,aAAa,EACb,WAAW,EACX,YAAY,EACb,MAAM,gBAAgB,CAAA;AACvB,OAAO,EACL,MAAM,EACN,YAAY,EACZ,OAAO,EACP,KAAK,eAAe,EACpB,KAAK,UAAU,EACf,KAAK,YAAY,EACjB,KAAK,WAAW,EAChB,KAAK,WAAW,EACjB,MAAM,WAAW,CAAA;AAClB,OAAO,EAAE,SAAS,EAAE,YAAY,EAAE,KAAK,gBAAgB,EAAE,KAAK,cAAc,EAAE,MAAM,iBAAiB,CAAA;AAErG,OAAO,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAA;AAMxD,OAAO,EACL,QAAQ,EACR,YAAY,EACZ,YAAY,EACZ,UAAU,EACV,YAAY,EACZ,aAAa,EACb,cAAc,EACd,WAAW,EACX,WAAW,EACX,KAAK,IAAI,IAAI,UAAU,EACvB,KAAK,aAAa,EACnB,MAAM,aAAa,CAAA;AAGpB,OAAO,EAAE,YAAY,EAAE,cAAc,EAAE,WAAW,EAAE,KAAK,aAAa,EAAE,KAAK,YAAY,EAAE,MAAM,WAAW,CAAA"}
|
package/dist/index.js
CHANGED
|
@@ -16,4 +16,11 @@ export { costOf, describeCost, scoreOf } from "./cost.js";
|
|
|
16
16
|
export { costCurve, costCurveSvg } from "./cost-chart.js";
|
|
17
17
|
/* 이미 컴파일된 청사진의 형태를 확인한다 — 서버·파일에서 온 것을 읽기 전에. */
|
|
18
18
|
export { blueprintProblems } from "./blueprint-shape.js";
|
|
19
|
+
/*
|
|
20
|
+
* 크기 반응 규칙 — **앵커의 뜻을 아는 자리.** things-scene 에서 옮겨 왔다(2026-09-09). 그리는 쪽과
|
|
21
|
+
* 발행 게이트가 같은 계산을 봐야 화면과 판정이 어긋나지 않는다.
|
|
22
|
+
*/
|
|
23
|
+
export { anchorOf, needsOwnMesh, repeatOffset, repeatPlan, REPEAT_LIMIT, rotatedExtent, sizingPosition, sizingScale, stretchAxis } from "./sizing.js";
|
|
24
|
+
/* 발행해도 되나 — 크기를 바꿔 봐야 아는 것들. */
|
|
25
|
+
export { sizingReport, sizingReportOf, SIZING_WAYS } from "./gate.js";
|
|
19
26
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,cAAc,YAAY,CAAA;AAC1B,OAAO,EAAE,QAAQ,EAAuB,MAAM,eAAe,CAAA;AAC7D,OAAO,EACL,OAAO,EACP,kBAAkB,EAClB,aAAa,EACb,aAAa,EACb,eAAe,EACf,aAAa,EACb,WAAW,EACX,YAAY,EACb,MAAM,gBAAgB,CAAA;AACvB,OAAO,EACL,MAAM,EACN,YAAY,EACZ,OAAO,EAMR,MAAM,WAAW,CAAA;AAClB,OAAO,EAAE,SAAS,EAAE,YAAY,EAA8C,MAAM,iBAAiB,CAAA;AACrG,iDAAiD;AACjD,OAAO,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAA"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,cAAc,YAAY,CAAA;AAC1B,OAAO,EAAE,QAAQ,EAAuB,MAAM,eAAe,CAAA;AAC7D,OAAO,EACL,OAAO,EACP,kBAAkB,EAClB,aAAa,EACb,aAAa,EACb,eAAe,EACf,aAAa,EACb,WAAW,EACX,YAAY,EACb,MAAM,gBAAgB,CAAA;AACvB,OAAO,EACL,MAAM,EACN,YAAY,EACZ,OAAO,EAMR,MAAM,WAAW,CAAA;AAClB,OAAO,EAAE,SAAS,EAAE,YAAY,EAA8C,MAAM,iBAAiB,CAAA;AACrG,iDAAiD;AACjD,OAAO,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAA;AAExD;;;GAGG;AACH,OAAO,EACL,QAAQ,EACR,YAAY,EACZ,YAAY,EACZ,UAAU,EACV,YAAY,EACZ,aAAa,EACb,cAAc,EACd,WAAW,EACX,WAAW,EAGZ,MAAM,aAAa,CAAA;AAEpB,gCAAgC;AAChC,OAAO,EAAE,YAAY,EAAE,cAAc,EAAE,WAAW,EAAyC,MAAM,WAAW,CAAA"}
|
package/dist/sizing.d.ts
ADDED
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
import type { AnchorRule, Axis, BlueprintMember, Vec3 } from './types.ts';
|
|
2
|
+
export type { Axis };
|
|
3
|
+
/**
|
|
4
|
+
* 인스턴스 크기가 바뀔 때 부품이 어떻게 반응하나.
|
|
5
|
+
*
|
|
6
|
+
* ## 왜 따로 떼어 두나
|
|
7
|
+
*
|
|
8
|
+
* 같은 답을 세 곳이 낸다 — 3D(`figure-real-object`), 2D 톱뷰(`figure-instance`),
|
|
9
|
+
* 그리고 속성 편집기. 저마다 계산하면 화면마다 다른 모양이 나오고, 그때는 어느 쪽이
|
|
10
|
+
* 맞는지 알 방법이 없다.
|
|
11
|
+
*
|
|
12
|
+
* ## 규칙 넷
|
|
13
|
+
*
|
|
14
|
+
* scale 비례 확대. 인스턴스 배율을 그대로 받는다 — 아무것도 하지 않아도 된다
|
|
15
|
+
* fixed 크기는 그대로. **붙잡은 자리에서 잰 거리**를 지킨다
|
|
16
|
+
* stretch 가장 길게 뻗은 축이 **양쪽 면 사이를 채운다**
|
|
17
|
+
* repeat 크기는 그대로 두고 **개수**가 늘어난다
|
|
18
|
+
*
|
|
19
|
+
* ## 자리도 규칙의 일부다
|
|
20
|
+
*
|
|
21
|
+
* 한동안 이 파일은 **크기**만 다뤘고 자리는 언제나 비례였다. 그래서 시그널 타워를
|
|
22
|
+
* 3 배로 세우면 기둥은 늘어나는데 램프들은 기둥 위 공중으로 흩어졌다.
|
|
23
|
+
*
|
|
24
|
+
* 1× foot 0..90 · pole 85..705 · bracket 703..747 · cap 1037..1087
|
|
25
|
+
* 3× foot 90..180 · pole 255..2115 · bracket 2153..2197 · cap 3161..3211
|
|
26
|
+
*
|
|
27
|
+
* 램프는 상자 안 어디쯤이 아니라 **기둥 꼭대기**에 붙어 있다. 그 말을 하는 것이
|
|
28
|
+
* 앵커다 — 부품이 어느 면에서 잰 거리를 지키는가.
|
|
29
|
+
*
|
|
30
|
+
* 세 가지가 한 규칙의 세 경우다. 축마다
|
|
31
|
+
*
|
|
32
|
+
* 아무 데도 안 붙잡는다 비례로 따라간다 `scale`
|
|
33
|
+
* 한 자리를 붙잡는다 거기서 잰 거리 유지 `fixed` · `repeat` 의 옆 축
|
|
34
|
+
* 두 면을 다 붙잡는다 가운데가 늘어나 채운다 `stretch` 의 긴 축
|
|
35
|
+
*
|
|
36
|
+
* 붙잡는 자리는 아래 면(`min`) · 가운데(`center`) · 위 면(`max`) 셋이다. 셋이 같은
|
|
37
|
+
* 규칙이다 — 기준이 어디냐만 다르다. 한동안 `center` 만 「비례로 밀린다」였는데, 그러면
|
|
38
|
+
* 가운데 가까이 저작한 것이 상자가 커질 때마다 밖으로 밀려 이웃과 갈라진다. 크레들의
|
|
39
|
+
* V 홈 패드 둘이 ±80 에서 ±240 으로 벌어져 축을 놓친 것이 그것이었다.
|
|
40
|
+
*
|
|
41
|
+
* 3D 도구의 나인슬라이스가 하는 일과 같고, 여기서는 그것이 세 축으로 있다.
|
|
42
|
+
*
|
|
43
|
+
* ## 어떻게 되돌리나
|
|
44
|
+
*
|
|
45
|
+
* 부모(`object3d`)가 인스턴스 배율 `S` 를 이미 걸고 있다. 그래서 크기를 그대로 두려면
|
|
46
|
+
* 자식이 `1/S` 로 되돌리면 된다. 자리는 부모의 배율을 그대로 받으므로 따라간다.
|
|
47
|
+
*
|
|
48
|
+
* 월드 = S · (자리 + (1/S) ⊙ 형상) = S·자리 + 형상
|
|
49
|
+
*
|
|
50
|
+
* 회전은 **형상에 미리 구워** 둔다. 그래야 위 식이 정확히 성립한다 — 회전을 mesh 에
|
|
51
|
+
* 걸면 비균등 배율이 회전 뒤에 곱해져 형상이 기울어진다.
|
|
52
|
+
*
|
|
53
|
+
* 이 방식의 값은 **geometry 를 그대로 나눠 쓴다**는 것이다. 인스턴스가 몇이든 정점
|
|
54
|
+
* 버퍼는 늘지 않는다. 대신 합칠 수 없어 draw call 이 부품 수만큼 는다 — 그 비용은
|
|
55
|
+
* 청사진의 묶음 수에 그대로 잡히고 성숙도가 잰다.
|
|
56
|
+
*/
|
|
57
|
+
/**
|
|
58
|
+
* 이 축에서 이 부품이 어떻게 서나. **크기와 자리를 함께 정하는 한 값이다.**
|
|
59
|
+
*
|
|
60
|
+
* 저작자가 적었으면 그것이 이기고, 없으면 `sizing` 이 정한다.
|
|
61
|
+
*
|
|
62
|
+
* fixed 가까운 면
|
|
63
|
+
* stretch 가장 긴 축은 `span`, 나머지는 가까운 면
|
|
64
|
+
* repeat 늘어나는 축은 `center`(줄이 제자리에 남는다), 나머지는 가까운 면
|
|
65
|
+
*
|
|
66
|
+
* **가까운 면**은 상자의 위 절반에 저작한 것은 위를, 아래 절반은 아래를 붙잡는 것이다.
|
|
67
|
+
* 사람이 램프를 꼭대기 근처에 놓을 때 뜻하는 것이 그것이다. 정확히 가운데면 `center` 이고,
|
|
68
|
+
* 그때는 비례로 따라가는 것이 맞다 — 어느 쪽도 더 가깝지 않기 때문이다.
|
|
69
|
+
*
|
|
70
|
+
* 세는 것은 **부품의 면에서 상자의 면까지**이지 중심에서가 아니다. 중심으로 재면
|
|
71
|
+
* 굵은 부품과 얇은 부품이 같은 자리에서 다른 답을 낸다.
|
|
72
|
+
*/
|
|
73
|
+
export declare function anchorOf(member: BlueprintMember, base: Vec3, axis: Axis): AnchorRule;
|
|
74
|
+
/** 인스턴스 배율. `bounds ÷ base` 다. */
|
|
75
|
+
export interface InstanceScale {
|
|
76
|
+
x: number;
|
|
77
|
+
y: number;
|
|
78
|
+
z: number;
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* 되돌릴 것이 있는 부품인가.
|
|
82
|
+
*
|
|
83
|
+
* `scale` 은 부모 배율을 그대로 받으면 되므로 합쳐 둔 채로 그린다. 나머지 셋은 따로
|
|
84
|
+
* 세운다.
|
|
85
|
+
*
|
|
86
|
+
* **곡면은 `scale` 이어도 따로 선다.** 합친 형상은 변환을 하나만 받는데, 인스턴스가
|
|
87
|
+
* 축마다 다른 배율이면 그 하나가 원기둥을 타원 기둥으로 만든다. 원기둥이라고 적어
|
|
88
|
+
* 놓고 원기둥이 아닌 것을 그리게 된다.
|
|
89
|
+
*
|
|
90
|
+
* 값이 있는 만큼 값을 치른다 — 곡면 부품 하나가 draw call 하나다. figure-model 의
|
|
91
|
+
* `standsAlone` 이 **같은 답**을 내야 한다. 갈리면 성숙도가 세는 수와 화면이 그리는
|
|
92
|
+
* 수가 달라진다.
|
|
93
|
+
*/
|
|
94
|
+
export declare function needsOwnMesh(member: BlueprintMember): boolean;
|
|
95
|
+
/**
|
|
96
|
+
* 회전까지 반영한 부품의 축별 크기.
|
|
97
|
+
*
|
|
98
|
+
* 회전한 상자의 여덟 꼭짓점을 각 축에 내린 것 — 축에 맞춘 경계다. 회전 행렬은
|
|
99
|
+
* `Rx·Ry·Rz` 이고 three 의 기본 Euler 순서('XYZ')와 같다. `memberGeometry` 가 같은
|
|
100
|
+
* 순서로 돌리므로 여기만 다르면 답이 갈린다.
|
|
101
|
+
*
|
|
102
|
+
* figure-model 의 `rotatedExtentOf` 와 같은 식이다. 그쪽이 정본이고 여기는 읽는 쪽의
|
|
103
|
+
* 사본이다 — 이 패키지는 figure-model 에 의존하지 않는다(`figure-blueprint.ts` 참고).
|
|
104
|
+
*/
|
|
105
|
+
export declare function rotatedExtent(member: BlueprintMember): Vec3;
|
|
106
|
+
/**
|
|
107
|
+
* `stretch` 일 때 늘어나는 축 — **가장 길게 뻗은 축**이다.
|
|
108
|
+
*
|
|
109
|
+
* 형식에 축을 적는 자리가 없어서 크기에서 읽는다. 프레임 · 벨트 · 레일이 전부 "길어서
|
|
110
|
+
* 그 물건인 것"이라 이 규칙과 맞는다. 같으면 x → z → y 순으로 정한다.
|
|
111
|
+
*/
|
|
112
|
+
export declare function stretchAxis(member: BlueprintMember): Axis;
|
|
113
|
+
/**
|
|
114
|
+
* 부품 mesh 에 걸 배율 — 부모가 건 인스턴스 배율을 **어디까지 되돌릴까**.
|
|
115
|
+
*
|
|
116
|
+
* `1` 은 인스턴스를 그대로 따라간다는 뜻이고, `1/S` 는 저작한 크기를 지킨다는 뜻이다.
|
|
117
|
+
*
|
|
118
|
+
* `repeat` 는 부품 자체의 크기를 지킨다 — 늘어나는 것은 개수다.
|
|
119
|
+
*/
|
|
120
|
+
export declare function sizingScale(member: BlueprintMember, scale: InstanceScale, base: Vec3): Vec3;
|
|
121
|
+
/**
|
|
122
|
+
* 부품을 놓을 자리 — **부모가 배율을 걸기 전의 자리**다.
|
|
123
|
+
*
|
|
124
|
+
* 부모(`object3d`)가 인스턴스 배율 `S` 를 걸므로, 월드에서 원하는 자리를 `S` 로 나눠
|
|
125
|
+
* 돌려준다. 그래서 `S = 1` 이면 언제나 저작한 자리 그대로다 — 저작 화면에서 보던 것이
|
|
126
|
+
* 인스턴스 배율 1 에서 그대로 선다.
|
|
127
|
+
*
|
|
128
|
+
* center 저작한 자리. 상자와 함께 비례로 밀린다
|
|
129
|
+
* min 아래 면에서 잰 거리를 지킨다
|
|
130
|
+
* max 위 면에서 잰 거리를 지킨다
|
|
131
|
+
* stretch 양쪽을 다 지키므로 자리는 두 끝의 가운데다
|
|
132
|
+
*/
|
|
133
|
+
export declare function sizingPosition(member: BlueprintMember, scale: InstanceScale, base: Vec3): Vec3;
|
|
134
|
+
/**
|
|
135
|
+
* `repeat` 를 몇 개로 펼치나.
|
|
136
|
+
*
|
|
137
|
+
* **기준 상자를 한 칸씩 채운다.** 저작자는 **단위 하나**를 그리고, 런타임이 그 축의
|
|
138
|
+
* 길이를 채운다. 3D 도구의 배열 변형이 "길이에 맞추기" 로 하는 일과 같다.
|
|
139
|
+
*
|
|
140
|
+
* 개수 = floor(기준 상자의 그 축 길이 × 인스턴스 배율 ÷ 한 칸)
|
|
141
|
+
*
|
|
142
|
+
* ## 한 칸은 **중심에서 다음 중심까지**다
|
|
143
|
+
*
|
|
144
|
+
* 부품 크기와 무관하다. 전에는 `부품 크기 + 틈` 으로 셌는데, 그러면 부품을 굵게 하거나
|
|
145
|
+
* 돌릴 때마다 줄 전체가 다시 깔린다. 롤러를 30° 기울였더니 축 방향 경계상자가 96 에서
|
|
146
|
+
* 343 으로 늘어 개수가 16 에서 6 으로 무너졌다. 기울어진 롤러 둘은 빗살처럼 나란히
|
|
147
|
+
* 놓이므로 그렇게 벌릴 이유가 없는데도 그랬다.
|
|
148
|
+
*
|
|
149
|
+
* 이제 기울여도 개수가 그대로다. **기울인 채로 바짝 붙여 까는 것**이 표현된다.
|
|
150
|
+
*
|
|
151
|
+
* ## 왜 부품 크기가 아니라 기준 상자를 채우나
|
|
152
|
+
*
|
|
153
|
+
* 전에는 "그 부품이 `scale` 이었다면 차지했을 만큼" 을 채웠다. 지름 96 짜리 롤러는
|
|
154
|
+
* 컨베이어를 3 배로 늘려도 288 밖에 안 되어 롤러가 한두 개 나온다. 2400 짜리 컨베이어에
|
|
155
|
+
* 롤러 하나는 컨베이어가 아니다.
|
|
156
|
+
*
|
|
157
|
+
* 롤러는 일정한 간격으로 전 구간에 깔린다. 길이가 두 배면 롤러도 두 배다.
|
|
158
|
+
*/
|
|
159
|
+
export declare function repeatPlan(member: BlueprintMember, scale: InstanceScale, base: Vec3): {
|
|
160
|
+
axis: Axis;
|
|
161
|
+
count: number;
|
|
162
|
+
pitch: number;
|
|
163
|
+
} | null;
|
|
164
|
+
/**
|
|
165
|
+
* 한 부품이 펼쳐질 수 있는 최대 개수.
|
|
166
|
+
*
|
|
167
|
+
* 복제본 하나가 draw call 하나다. 인스턴스를 아주 크게 늘리면 개수가 끝없이 늘어 한
|
|
168
|
+
* 자산이 프레임을 다 먹는다. 그 지점에서는 이미 낱개를 셀 수 없으므로 더 늘려도 보이는
|
|
169
|
+
* 것이 달라지지 않는다.
|
|
170
|
+
*/
|
|
171
|
+
export declare const REPEAT_LIMIT = 100;
|
|
172
|
+
/**
|
|
173
|
+
* 복제본 하나의 자리 — 저작한 자리를 가운데 두고 양쪽으로 벌린다.
|
|
174
|
+
*
|
|
175
|
+
* 한쪽으로만 늘어놓으면 부품이 커질 때마다 한 방향으로 밀려서, 저작할 때 맞춰 둔 자리가
|
|
176
|
+
* 어긋난다. 가운데를 지키면 대칭으로 놓은 것들이 계속 대칭이다.
|
|
177
|
+
*/
|
|
178
|
+
export declare function repeatOffset(index: number, count: number, pitch: number): number;
|
|
179
|
+
//# sourceMappingURL=sizing.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sizing.d.ts","sourceRoot":"","sources":["../src/sizing.ts"],"names":[],"mappings":"AAiBA,OAAO,KAAK,EAAE,UAAU,EAAE,IAAI,EAAE,eAAe,EAAE,IAAI,EAAE,MAAM,YAAY,CAAA;AAEzE,YAAY,EAAE,IAAI,EAAE,CAAA;AAEpB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqDG;AAEH;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,QAAQ,CACtB,MAAM,EAAE,eAAe,EACvB,IAAI,EAAE,IAAI,EACV,IAAI,EAAE,IAAI,GACT,UAAU,CAYZ;AAuCD,kCAAkC;AAClC,MAAM,WAAW,aAAa;IAC5B,CAAC,EAAE,MAAM,CAAA;IACT,CAAC,EAAE,MAAM,CAAA;IACT,CAAC,EAAE,MAAM,CAAA;CACV;AAGD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,eAAe,GAAG,OAAO,CAE7D;AAeD;;;;;;;;;GASG;AACH,wBAAgB,aAAa,CAAC,MAAM,EAAE,eAAe,GAAG,IAAI,CAsB3D;AAED;;;;;GAKG;AACH,wBAAgB,WAAW,CAAC,MAAM,EAAE,eAAe,GAAG,IAAI,CAKzD;AAED;;;;;;GAMG;AACH,wBAAgB,WAAW,CACzB,MAAM,EAAE,eAAe,EACvB,KAAK,EAAE,aAAa,EACpB,IAAI,EAAE,IAAI,GACT,IAAI,CAkDN;AAiHD;;;;;;;;;;;GAWG;AACH,wBAAgB,cAAc,CAC5B,MAAM,EAAE,eAAe,EACvB,KAAK,EAAE,aAAa,EACpB,IAAI,EAAE,IAAI,GACT,IAAI,CA4CN;AASD;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,wBAAgB,UAAU,CACxB,MAAM,EAAE,eAAe,EACvB,KAAK,EAAE,aAAa,EACpB,IAAI,EAAE,IAAI,GACT;IAAE,IAAI,EAAE,IAAI,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAwBrD;AAED;;;;;;GAMG;AACH,eAAO,MAAM,YAAY,MAAM,CAAA;AAE/B;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAEhF"}
|
package/dist/sizing.js
ADDED
|
@@ -0,0 +1,475 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright © HatioLab Inc. All rights reserved.
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* 인스턴스 크기가 바뀔 때 부품이 어떻게 반응하나.
|
|
6
|
+
*
|
|
7
|
+
* ## 왜 따로 떼어 두나
|
|
8
|
+
*
|
|
9
|
+
* 같은 답을 세 곳이 낸다 — 3D(`figure-real-object`), 2D 톱뷰(`figure-instance`),
|
|
10
|
+
* 그리고 속성 편집기. 저마다 계산하면 화면마다 다른 모양이 나오고, 그때는 어느 쪽이
|
|
11
|
+
* 맞는지 알 방법이 없다.
|
|
12
|
+
*
|
|
13
|
+
* ## 규칙 넷
|
|
14
|
+
*
|
|
15
|
+
* scale 비례 확대. 인스턴스 배율을 그대로 받는다 — 아무것도 하지 않아도 된다
|
|
16
|
+
* fixed 크기는 그대로. **붙잡은 자리에서 잰 거리**를 지킨다
|
|
17
|
+
* stretch 가장 길게 뻗은 축이 **양쪽 면 사이를 채운다**
|
|
18
|
+
* repeat 크기는 그대로 두고 **개수**가 늘어난다
|
|
19
|
+
*
|
|
20
|
+
* ## 자리도 규칙의 일부다
|
|
21
|
+
*
|
|
22
|
+
* 한동안 이 파일은 **크기**만 다뤘고 자리는 언제나 비례였다. 그래서 시그널 타워를
|
|
23
|
+
* 3 배로 세우면 기둥은 늘어나는데 램프들은 기둥 위 공중으로 흩어졌다.
|
|
24
|
+
*
|
|
25
|
+
* 1× foot 0..90 · pole 85..705 · bracket 703..747 · cap 1037..1087
|
|
26
|
+
* 3× foot 90..180 · pole 255..2115 · bracket 2153..2197 · cap 3161..3211
|
|
27
|
+
*
|
|
28
|
+
* 램프는 상자 안 어디쯤이 아니라 **기둥 꼭대기**에 붙어 있다. 그 말을 하는 것이
|
|
29
|
+
* 앵커다 — 부품이 어느 면에서 잰 거리를 지키는가.
|
|
30
|
+
*
|
|
31
|
+
* 세 가지가 한 규칙의 세 경우다. 축마다
|
|
32
|
+
*
|
|
33
|
+
* 아무 데도 안 붙잡는다 비례로 따라간다 `scale`
|
|
34
|
+
* 한 자리를 붙잡는다 거기서 잰 거리 유지 `fixed` · `repeat` 의 옆 축
|
|
35
|
+
* 두 면을 다 붙잡는다 가운데가 늘어나 채운다 `stretch` 의 긴 축
|
|
36
|
+
*
|
|
37
|
+
* 붙잡는 자리는 아래 면(`min`) · 가운데(`center`) · 위 면(`max`) 셋이다. 셋이 같은
|
|
38
|
+
* 규칙이다 — 기준이 어디냐만 다르다. 한동안 `center` 만 「비례로 밀린다」였는데, 그러면
|
|
39
|
+
* 가운데 가까이 저작한 것이 상자가 커질 때마다 밖으로 밀려 이웃과 갈라진다. 크레들의
|
|
40
|
+
* V 홈 패드 둘이 ±80 에서 ±240 으로 벌어져 축을 놓친 것이 그것이었다.
|
|
41
|
+
*
|
|
42
|
+
* 3D 도구의 나인슬라이스가 하는 일과 같고, 여기서는 그것이 세 축으로 있다.
|
|
43
|
+
*
|
|
44
|
+
* ## 어떻게 되돌리나
|
|
45
|
+
*
|
|
46
|
+
* 부모(`object3d`)가 인스턴스 배율 `S` 를 이미 걸고 있다. 그래서 크기를 그대로 두려면
|
|
47
|
+
* 자식이 `1/S` 로 되돌리면 된다. 자리는 부모의 배율을 그대로 받으므로 따라간다.
|
|
48
|
+
*
|
|
49
|
+
* 월드 = S · (자리 + (1/S) ⊙ 형상) = S·자리 + 형상
|
|
50
|
+
*
|
|
51
|
+
* 회전은 **형상에 미리 구워** 둔다. 그래야 위 식이 정확히 성립한다 — 회전을 mesh 에
|
|
52
|
+
* 걸면 비균등 배율이 회전 뒤에 곱해져 형상이 기울어진다.
|
|
53
|
+
*
|
|
54
|
+
* 이 방식의 값은 **geometry 를 그대로 나눠 쓴다**는 것이다. 인스턴스가 몇이든 정점
|
|
55
|
+
* 버퍼는 늘지 않는다. 대신 합칠 수 없어 draw call 이 부품 수만큼 는다 — 그 비용은
|
|
56
|
+
* 청사진의 묶음 수에 그대로 잡히고 성숙도가 잰다.
|
|
57
|
+
*/
|
|
58
|
+
/**
|
|
59
|
+
* 이 축에서 이 부품이 어떻게 서나. **크기와 자리를 함께 정하는 한 값이다.**
|
|
60
|
+
*
|
|
61
|
+
* 저작자가 적었으면 그것이 이기고, 없으면 `sizing` 이 정한다.
|
|
62
|
+
*
|
|
63
|
+
* fixed 가까운 면
|
|
64
|
+
* stretch 가장 긴 축은 `span`, 나머지는 가까운 면
|
|
65
|
+
* repeat 늘어나는 축은 `center`(줄이 제자리에 남는다), 나머지는 가까운 면
|
|
66
|
+
*
|
|
67
|
+
* **가까운 면**은 상자의 위 절반에 저작한 것은 위를, 아래 절반은 아래를 붙잡는 것이다.
|
|
68
|
+
* 사람이 램프를 꼭대기 근처에 놓을 때 뜻하는 것이 그것이다. 정확히 가운데면 `center` 이고,
|
|
69
|
+
* 그때는 비례로 따라가는 것이 맞다 — 어느 쪽도 더 가깝지 않기 때문이다.
|
|
70
|
+
*
|
|
71
|
+
* 세는 것은 **부품의 면에서 상자의 면까지**이지 중심에서가 아니다. 중심으로 재면
|
|
72
|
+
* 굵은 부품과 얇은 부품이 같은 자리에서 다른 답을 낸다.
|
|
73
|
+
*/
|
|
74
|
+
export function anchorOf(member, base, axis) {
|
|
75
|
+
const said = member.anchor?.[axis];
|
|
76
|
+
if (said)
|
|
77
|
+
return said;
|
|
78
|
+
if (member.sizing === 'scale')
|
|
79
|
+
return 'scale';
|
|
80
|
+
if (member.sizing === 'stretch' && axis === stretchAxis(member))
|
|
81
|
+
return 'span';
|
|
82
|
+
if (member.sizing === 'repeat' && axis === member.repeat?.axis)
|
|
83
|
+
return 'center';
|
|
84
|
+
const gaps = clearance(member, base, axis);
|
|
85
|
+
if (gaps.min < gaps.max)
|
|
86
|
+
return 'min';
|
|
87
|
+
if (gaps.max < gaps.min)
|
|
88
|
+
return 'max';
|
|
89
|
+
return 'center';
|
|
90
|
+
}
|
|
91
|
+
/** 부품의 면에서 상자의 면까지 — 지켜야 할 거리 둘. */
|
|
92
|
+
function clearance(member, base, axis) {
|
|
93
|
+
const half = (Number.isFinite(base[axis]) ? base[axis] : 0) / 2;
|
|
94
|
+
const at = member.transform.position[axis];
|
|
95
|
+
const reach = rotatedExtent(member)[axis] / 2;
|
|
96
|
+
return { min: at - reach + half, max: half - (at + reach) };
|
|
97
|
+
}
|
|
98
|
+
/** 0 이나 음수 배율을 그대로 쓰지 않는다 — 막 놓은 인스턴스가 실제로 0 이다. */
|
|
99
|
+
function safeScale(value) {
|
|
100
|
+
return Number.isFinite(value) && value > 0 ? value : 1;
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* 늘어나는 축이 실제로 차지할 길이.
|
|
104
|
+
*
|
|
105
|
+
* 양쪽 여유를 지키고 가운데가 남는 만큼을 먹는다. 저작할 때의 여유가 그대로 남으므로
|
|
106
|
+
* 기둥이 발판과 브래킷 **사이**를 정확히 잇는다.
|
|
107
|
+
*
|
|
108
|
+
* 상자가 여유 둘을 합친 것보다 작아지면 남는 것이 없다. 그때는 0 이 아니라 실오라기를
|
|
109
|
+
* 남긴다 — 배율 0 인 mesh 는 법선 행렬이 특이해져 조명이 NaN 이 된다.
|
|
110
|
+
*/
|
|
111
|
+
function spanLength(member, scale, base, axis) {
|
|
112
|
+
const gaps = clearance(member, base, axis);
|
|
113
|
+
const room = (Number.isFinite(base[axis]) ? base[axis] : 0) * safeScale(scale[axis]);
|
|
114
|
+
return Math.max(room - gaps.min - gaps.max, SLIVER);
|
|
115
|
+
}
|
|
116
|
+
/** 사라지지 않을 만큼. 위 주석 참고. */
|
|
117
|
+
const SLIVER = 1e-3;
|
|
118
|
+
/**
|
|
119
|
+
* 되돌릴 것이 있는 부품인가.
|
|
120
|
+
*
|
|
121
|
+
* `scale` 은 부모 배율을 그대로 받으면 되므로 합쳐 둔 채로 그린다. 나머지 셋은 따로
|
|
122
|
+
* 세운다.
|
|
123
|
+
*
|
|
124
|
+
* **곡면은 `scale` 이어도 따로 선다.** 합친 형상은 변환을 하나만 받는데, 인스턴스가
|
|
125
|
+
* 축마다 다른 배율이면 그 하나가 원기둥을 타원 기둥으로 만든다. 원기둥이라고 적어
|
|
126
|
+
* 놓고 원기둥이 아닌 것을 그리게 된다.
|
|
127
|
+
*
|
|
128
|
+
* 값이 있는 만큼 값을 치른다 — 곡면 부품 하나가 draw call 하나다. figure-model 의
|
|
129
|
+
* `standsAlone` 이 **같은 답**을 내야 한다. 갈리면 성숙도가 세는 수와 화면이 그리는
|
|
130
|
+
* 수가 달라진다.
|
|
131
|
+
*/
|
|
132
|
+
export function needsOwnMesh(member) {
|
|
133
|
+
return member.sizing !== 'scale' || isCurved(member);
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* 단면을 원으로 지키는 부품인가.
|
|
137
|
+
*
|
|
138
|
+
* 곡면만 지킬 수 있고, 저작자가 끄지 않는 한 지킨다. 끄면 합친 묶음에 들어가 draw call
|
|
139
|
+
* 을 아끼는 대신 인스턴스 배율대로 찌그러진다 — 볼트 머리처럼 아무도 안 볼 것에 쓴다.
|
|
140
|
+
*
|
|
141
|
+
* figure-model 의 `keepsRound` 와 **같은 답**을 내야 한다.
|
|
142
|
+
*/
|
|
143
|
+
function isCurved(member) {
|
|
144
|
+
if (member.primitive !== 'cylinder' && member.primitive !== 'sphere')
|
|
145
|
+
return false;
|
|
146
|
+
return member.keepRound !== false;
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* 회전까지 반영한 부품의 축별 크기.
|
|
150
|
+
*
|
|
151
|
+
* 회전한 상자의 여덟 꼭짓점을 각 축에 내린 것 — 축에 맞춘 경계다. 회전 행렬은
|
|
152
|
+
* `Rx·Ry·Rz` 이고 three 의 기본 Euler 순서('XYZ')와 같다. `memberGeometry` 가 같은
|
|
153
|
+
* 순서로 돌리므로 여기만 다르면 답이 갈린다.
|
|
154
|
+
*
|
|
155
|
+
* figure-model 의 `rotatedExtentOf` 와 같은 식이다. 그쪽이 정본이고 여기는 읽는 쪽의
|
|
156
|
+
* 사본이다 — 이 패키지는 figure-model 에 의존하지 않는다(`figure-blueprint.ts` 참고).
|
|
157
|
+
*/
|
|
158
|
+
export function rotatedExtent(member) {
|
|
159
|
+
const { size, rotation } = member.transform;
|
|
160
|
+
if (!rotation)
|
|
161
|
+
return { ...size };
|
|
162
|
+
const rad = Math.PI / 180;
|
|
163
|
+
const cx = Math.cos((rotation.x ?? 0) * rad);
|
|
164
|
+
const sx = Math.sin((rotation.x ?? 0) * rad);
|
|
165
|
+
const cy = Math.cos((rotation.y ?? 0) * rad);
|
|
166
|
+
const sy = Math.sin((rotation.y ?? 0) * rad);
|
|
167
|
+
const cz = Math.cos((rotation.z ?? 0) * rad);
|
|
168
|
+
const sz = Math.sin((rotation.z ?? 0) * rad);
|
|
169
|
+
const rows = [
|
|
170
|
+
[cy * cz, -cy * sz, sy],
|
|
171
|
+
[sx * sy * cz + cx * sz, -sx * sy * sz + cx * cz, -sx * cy],
|
|
172
|
+
[-cx * sy * cz + sx * sz, cx * sy * sz + sx * cz, cx * cy]
|
|
173
|
+
];
|
|
174
|
+
const along = (row) => Math.abs(row[0]) * size.x + Math.abs(row[1]) * size.y + Math.abs(row[2]) * size.z;
|
|
175
|
+
return { x: along(rows[0]), y: along(rows[1]), z: along(rows[2]) };
|
|
176
|
+
}
|
|
177
|
+
/**
|
|
178
|
+
* `stretch` 일 때 늘어나는 축 — **가장 길게 뻗은 축**이다.
|
|
179
|
+
*
|
|
180
|
+
* 형식에 축을 적는 자리가 없어서 크기에서 읽는다. 프레임 · 벨트 · 레일이 전부 "길어서
|
|
181
|
+
* 그 물건인 것"이라 이 규칙과 맞는다. 같으면 x → z → y 순으로 정한다.
|
|
182
|
+
*/
|
|
183
|
+
export function stretchAxis(member) {
|
|
184
|
+
const { x, y, z } = rotatedExtent(member);
|
|
185
|
+
if (x >= z && x >= y)
|
|
186
|
+
return 'x';
|
|
187
|
+
if (z >= y)
|
|
188
|
+
return 'z';
|
|
189
|
+
return 'y';
|
|
190
|
+
}
|
|
191
|
+
/**
|
|
192
|
+
* 부품 mesh 에 걸 배율 — 부모가 건 인스턴스 배율을 **어디까지 되돌릴까**.
|
|
193
|
+
*
|
|
194
|
+
* `1` 은 인스턴스를 그대로 따라간다는 뜻이고, `1/S` 는 저작한 크기를 지킨다는 뜻이다.
|
|
195
|
+
*
|
|
196
|
+
* `repeat` 는 부품 자체의 크기를 지킨다 — 늘어나는 것은 개수다.
|
|
197
|
+
*/
|
|
198
|
+
export function sizingScale(member, scale, base) {
|
|
199
|
+
/*
|
|
200
|
+
**규칙은 축마다 정해진다.** 그것을 먼저 받아 둔다.
|
|
201
|
+
|
|
202
|
+
한동안 이 자리에 `if (member.sizing === 'scale') return flat` 이 있었다. `sizing` 이 없으면
|
|
203
|
+
컴파일이 그 값을 `'scale'` 로 채우므로, **`anchor` 만 적은 부품은 여기서 통째로 빠져나가
|
|
204
|
+
앵커가 조용히 무시되었다** — 크기도 자리도 비례로만 움직였다. 표본들이 `sizing` 을 쓰고
|
|
205
|
+
있어서 여태 드러나지 않았고, 발행 게이트를 만들며 `anchor` 만 쓴 시험이 그것을 잡았다.
|
|
206
|
+
|
|
207
|
+
`anchorOf` 가 이미 우선순위를 안다 — 저작자가 적은 `anchor` 가 이기고, 없으면 `sizing` 이
|
|
208
|
+
정한다. 그러니 판정은 그 함수에만 두고, 빠른 길은 **셋 다 `scale` 로 판정된 때**만 탄다.
|
|
209
|
+
*/
|
|
210
|
+
const rules = { x: anchorOf(member, base, 'x'), y: anchorOf(member, base, 'y'), z: anchorOf(member, base, 'z') };
|
|
211
|
+
if (AXES.every(axis => rules[axis] === 'scale')) {
|
|
212
|
+
/*
|
|
213
|
+
비례 확대는 되돌릴 것이 없다 — **곡면이 아니면.** 곡면은 축마다 다른 배율을 받으면
|
|
214
|
+
단면이 타원이 되므로 그때는 되돌린다.
|
|
215
|
+
|
|
216
|
+
3D 는 이 함수를 비-`scale` 부품에만 부르지만 2D 는 **모든 부품에** 부른다. 여기서
|
|
217
|
+
걸러 두지 않으면 평범한 부품까지 1/S 로 되돌아가 인스턴스를 키워도 그대로였다 —
|
|
218
|
+
시험이 그것을 잡았다.
|
|
219
|
+
*/
|
|
220
|
+
const flat = { x: 1, y: 1, z: 1 };
|
|
221
|
+
keepRound(member, scale, flat);
|
|
222
|
+
return flat;
|
|
223
|
+
}
|
|
224
|
+
const undo = { x: safeUndo(scale.x), y: safeUndo(scale.y), z: safeUndo(scale.z) };
|
|
225
|
+
for (const axis of AXES) {
|
|
226
|
+
const rule = rules[axis];
|
|
227
|
+
// 아무 면도 안 붙잡는 축은 부모가 건 배율을 그대로 받는다 — 되돌릴 것이 없다.
|
|
228
|
+
if (rule === 'scale')
|
|
229
|
+
undo[axis] = 1;
|
|
230
|
+
if (rule !== 'span')
|
|
231
|
+
continue;
|
|
232
|
+
/*
|
|
233
|
+
양쪽을 다 붙잡은 축은 **여유를 지키고 남는 만큼**을 먹는다. 인스턴스 배율을 그대로
|
|
234
|
+
받게 두면(전에 `stretch` 가 그랬다) 기둥이 상자와 같은 비율로만 자라서, 끝에 붙여
|
|
235
|
+
둔 부품과의 사이에 틈이 벌어진다.
|
|
236
|
+
|
|
237
|
+
부모가 이미 `S` 를 걸고 있으므로 여기서는 원하는 총 배율을 `S` 로 나눠 넘긴다.
|
|
238
|
+
*/
|
|
239
|
+
const own = rotatedExtent(member)[axis];
|
|
240
|
+
undo[axis] = own > 0 ? spanLength(member, scale, base, axis) / own / safeScale(scale[axis]) : 1;
|
|
241
|
+
}
|
|
242
|
+
keepRound(member, scale, undo);
|
|
243
|
+
followAspect(member, base, scale, undo);
|
|
244
|
+
return undo;
|
|
245
|
+
}
|
|
246
|
+
/**
|
|
247
|
+
* 다른 축의 배율을 따라간다 — **비율을 지킨다.**
|
|
248
|
+
*
|
|
249
|
+
* 드라이룸의 출입구가 그렇다. 방을 키우면 문도 커지지만 문은 문이라 폭이 높이에
|
|
250
|
+
* 비례해야 한다. `scale` 로 두면 폭이 제 축을 따라가므로, 방을 폭으로만 늘리면 문이
|
|
251
|
+
* 넓어지기만 하고 높아지지 않는다.
|
|
252
|
+
*
|
|
253
|
+
* 가리킨 축이 **끝난 뒤의** 배율을 따른다 — 그 축이 `span` 이면 채운 만큼, `fixed` 면 1,
|
|
254
|
+
* `scale` 이면 인스턴스 배율이다. 그래서 이 함수는 다른 규칙이 다 정해진 다음에 돈다.
|
|
255
|
+
* 형식이 `aspect-` 가 또 다른 `aspect-` 를 가리키는 것을 막으므로 한 번만 돌면 된다.
|
|
256
|
+
*
|
|
257
|
+
* ## 상자로 자르지 않는다
|
|
258
|
+
*
|
|
259
|
+
* 한동안 저작할 때의 여유를 넘지 않게 잘랐다. 문이 방보다 넓어지는 것을 막으려던 것인데,
|
|
260
|
+
* 그러면 **롤이 막힌다** — 크레들이 길어질 때 롤 지름이 폭을 따라 커지는 것이 이 규칙을
|
|
261
|
+
* 쓰는 다른 절반이고, 지름은 기준 상자의 높이를 넘어서 자란다.
|
|
262
|
+
*
|
|
263
|
+
* 자르지 않는 이유는 기준 상자가 담장이 아니기 때문이다. 배치 비율의 분모이고, 넘는
|
|
264
|
+
* 부품은 이미 있다(컨베이어의 발판이 상자보다 넓다).
|
|
265
|
+
*
|
|
266
|
+
* 대신 값이 있다. 이미 벽을 꽉 채운 문은 높이만 커진 방에서 벽보다 넓어진다 — 그것은
|
|
267
|
+
* 규칙의 흠이 아니라 「벽을 꽉 채운 것이 비율을 지킬 수는 없다」는 기하다. 그런 부품은
|
|
268
|
+
* 여유를 두고 저작하거나 `span` 으로 채운다.
|
|
269
|
+
*/
|
|
270
|
+
function followAspect(member, base, scale, undo) {
|
|
271
|
+
const settled = { x: safeScale(scale.x) * undo.x, y: safeScale(scale.y) * undo.y, z: safeScale(scale.z) * undo.z };
|
|
272
|
+
for (const axis of AXES) {
|
|
273
|
+
const named = aspectOf(anchorOf(member, base, axis));
|
|
274
|
+
if (!named)
|
|
275
|
+
continue;
|
|
276
|
+
undo[axis] = settled[named] / safeScale(scale[axis]);
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
/** `aspect-y` 처럼 적혀 있으면 가리킨 축, 아니면 null. */
|
|
280
|
+
function aspectOf(rule) {
|
|
281
|
+
if (rule === 'aspect-x')
|
|
282
|
+
return 'x';
|
|
283
|
+
if (rule === 'aspect-y')
|
|
284
|
+
return 'y';
|
|
285
|
+
if (rule === 'aspect-z')
|
|
286
|
+
return 'z';
|
|
287
|
+
return null;
|
|
288
|
+
}
|
|
289
|
+
/**
|
|
290
|
+
* 곡면 프리미티브의 단면은 **원이다.**
|
|
291
|
+
*
|
|
292
|
+
* 축마다 다른 배율을 받으면 원기둥이 타원 기둥이 된다. 크레들을 3 배로 세웠더니 롤의
|
|
293
|
+
* 지름이 세로로만 3 배가 되어 납작한 타원이 나왔다 — 원기둥이라고 적어 놓고 원기둥이
|
|
294
|
+
* 아닌 것을 그린 것이다.
|
|
295
|
+
*
|
|
296
|
+
* 그래서 단면의 두 축은 **같은 배율**을 받는다. 두 배율의 **기하평균**이다.
|
|
297
|
+
*
|
|
298
|
+
* 작은 쪽을 쓰면 크기까지 얼어붙는다 — 한 축만 늘인 인스턴스에서 지름이 1 배로 묶여,
|
|
299
|
+
* 형태가 아니라 크기를 지키게 된다. 큰 쪽을 쓰면 반대로 좁은 축에서 크게 뚫고 나간다.
|
|
300
|
+
* 기하평균은 둘 다 따라가면서 원을 지키고, `effectiveDepth` 가 높이를 정할 때 쓰는 것과
|
|
301
|
+
* 같은 셈이다 — 한 축만 늘여도 덜 왜곡된다.
|
|
302
|
+
*
|
|
303
|
+
* 좁은 축의 상자를 얼마간 넘을 수 있다. 기준 상자는 배치 비율의 분모이지 담장이 아니고,
|
|
304
|
+
* 넘는 부품은 이미 있다(컨베이어의 발판이 상자보다 넓다).
|
|
305
|
+
*
|
|
306
|
+
* 축이 어느 쪽인지는 회전을 반영해 정한다. `CylinderGeometry` 의 축은 돌리기 전 y 이고,
|
|
307
|
+
* 그것을 부품의 회전으로 옮긴 뒤 가장 큰 성분이 있는 축이 그 부품의 축이다. 구는 축이
|
|
308
|
+
* 없으므로 세 축이 다 단면이다.
|
|
309
|
+
*
|
|
310
|
+
* `polygon` · `rect` 는 저작자가 점을 찍은 단면이라 건드리지 않는다. 타원으로 만들고
|
|
311
|
+
* 싶으면 그것으로 만든다.
|
|
312
|
+
*/
|
|
313
|
+
function keepRound(member, scale, undo) {
|
|
314
|
+
if (!isCurved(member))
|
|
315
|
+
return;
|
|
316
|
+
const spin = member.primitive === 'sphere' ? null : longAxis(member);
|
|
317
|
+
const across = AXES.filter(axis => axis !== spin);
|
|
318
|
+
let product = 1;
|
|
319
|
+
for (const axis of across)
|
|
320
|
+
product *= safeScale(scale[axis]) * undo[axis];
|
|
321
|
+
if (!(product > 0) || !Number.isFinite(product))
|
|
322
|
+
return;
|
|
323
|
+
const even = Math.pow(product, 1 / across.length);
|
|
324
|
+
for (const axis of across)
|
|
325
|
+
undo[axis] = even / safeScale(scale[axis]);
|
|
326
|
+
}
|
|
327
|
+
/** 원기둥의 축 — 돌리기 전 y 를 부품의 회전으로 옮겨 가장 크게 놓인 축. */
|
|
328
|
+
function longAxis(member) {
|
|
329
|
+
const rotation = member.transform.rotation;
|
|
330
|
+
if (!rotation)
|
|
331
|
+
return 'y';
|
|
332
|
+
const rad = Math.PI / 180;
|
|
333
|
+
const cx = Math.cos((rotation.x ?? 0) * rad);
|
|
334
|
+
const sx = Math.sin((rotation.x ?? 0) * rad);
|
|
335
|
+
const cy = Math.cos((rotation.y ?? 0) * rad);
|
|
336
|
+
const cz = Math.cos((rotation.z ?? 0) * rad);
|
|
337
|
+
const sz = Math.sin((rotation.z ?? 0) * rad);
|
|
338
|
+
const sy = Math.sin((rotation.y ?? 0) * rad);
|
|
339
|
+
// Rx·Ry·Rz 의 둘째 열 — (0, 1, 0) 이 어디로 가나.
|
|
340
|
+
const moved = {
|
|
341
|
+
x: -cy * sz,
|
|
342
|
+
y: -sx * sy * sz + cx * cz,
|
|
343
|
+
z: cx * sy * sz + sx * cz
|
|
344
|
+
};
|
|
345
|
+
const size = { x: Math.abs(moved.x), y: Math.abs(moved.y), z: Math.abs(moved.z) };
|
|
346
|
+
if (size.x >= size.y && size.x >= size.z)
|
|
347
|
+
return 'x';
|
|
348
|
+
return size.z >= size.y ? 'z' : 'y';
|
|
349
|
+
}
|
|
350
|
+
/**
|
|
351
|
+
* 부품을 놓을 자리 — **부모가 배율을 걸기 전의 자리**다.
|
|
352
|
+
*
|
|
353
|
+
* 부모(`object3d`)가 인스턴스 배율 `S` 를 걸므로, 월드에서 원하는 자리를 `S` 로 나눠
|
|
354
|
+
* 돌려준다. 그래서 `S = 1` 이면 언제나 저작한 자리 그대로다 — 저작 화면에서 보던 것이
|
|
355
|
+
* 인스턴스 배율 1 에서 그대로 선다.
|
|
356
|
+
*
|
|
357
|
+
* center 저작한 자리. 상자와 함께 비례로 밀린다
|
|
358
|
+
* min 아래 면에서 잰 거리를 지킨다
|
|
359
|
+
* max 위 면에서 잰 거리를 지킨다
|
|
360
|
+
* stretch 양쪽을 다 지키므로 자리는 두 끝의 가운데다
|
|
361
|
+
*/
|
|
362
|
+
export function sizingPosition(member, scale, base) {
|
|
363
|
+
const { position } = member.transform;
|
|
364
|
+
/*
|
|
365
|
+
같은 이유로 `sizing` 을 직접 보지 않는다(§`sizingScale`) — `anchor` 만 적은 부품이 여기서
|
|
366
|
+
빠져나가면 자리가 비례로만 밀려, 크기는 지켜지는데 자리는 안 지켜지는 반쪽이 된다.
|
|
367
|
+
*/
|
|
368
|
+
const rules = { x: anchorOf(member, base, 'x'), y: anchorOf(member, base, 'y'), z: anchorOf(member, base, 'z') };
|
|
369
|
+
if (AXES.every(axis => rules[axis] === 'scale'))
|
|
370
|
+
return { ...position };
|
|
371
|
+
const out = { ...position };
|
|
372
|
+
// 비율을 따라가는 축이 있으면 그 축이 **끝낸** 배율이 필요하다.
|
|
373
|
+
const sized = sizingScale(member, scale, base);
|
|
374
|
+
const worldFactor = (axis) => safeScale(scale[axis]) * sized[axis];
|
|
375
|
+
for (const axis of AXES) {
|
|
376
|
+
const rule = rules[axis];
|
|
377
|
+
// 붙잡지 않는 축만 부모의 배율에 자리를 맡긴다.
|
|
378
|
+
if (rule === 'scale')
|
|
379
|
+
continue;
|
|
380
|
+
/*
|
|
381
|
+
비율을 따라가는 축은 자리도 따라간다. 문에 붙은 표시등이 문과 함께 커지면서 문의
|
|
382
|
+
같은 자리에 남아야 하고, 그것은 자리에도 같은 배율이 걸려야 성립한다.
|
|
383
|
+
*/
|
|
384
|
+
const named = aspectOf(rule);
|
|
385
|
+
if (named) {
|
|
386
|
+
out[axis] = (position[axis] * worldFactor(named)) / safeScale(scale[axis]);
|
|
387
|
+
continue;
|
|
388
|
+
}
|
|
389
|
+
const factor = safeScale(scale[axis]);
|
|
390
|
+
const half = (Number.isFinite(base[axis]) ? base[axis] : 0) / 2;
|
|
391
|
+
const gaps = clearance(member, base, axis);
|
|
392
|
+
const reach = rotatedExtent(member)[axis] / 2;
|
|
393
|
+
if (rule === 'span')
|
|
394
|
+
out[axis] = (-half * factor + gaps.min + spanLength(member, scale, base, axis) / 2) / factor;
|
|
395
|
+
else if (rule === 'min')
|
|
396
|
+
out[axis] = (-half * factor + gaps.min + reach) / factor;
|
|
397
|
+
else if (rule === 'max')
|
|
398
|
+
out[axis] = (half * factor - gaps.max - reach) / factor;
|
|
399
|
+
// center — 가운데에서 잰 거리를 지킨다. 부모가 배율을 걸므로 나눠서 넘긴다.
|
|
400
|
+
else
|
|
401
|
+
out[axis] = position[axis] / factor;
|
|
402
|
+
}
|
|
403
|
+
return out;
|
|
404
|
+
}
|
|
405
|
+
const AXES = ['x', 'y', 'z'];
|
|
406
|
+
/** 0 이나 음수로 나누지 않는다 — 인스턴스 크기가 0 인 순간이 실제로 있다(막 놓았을 때). */
|
|
407
|
+
function safeUndo(value) {
|
|
408
|
+
return Number.isFinite(value) && value > 0 ? 1 / value : 1;
|
|
409
|
+
}
|
|
410
|
+
/**
|
|
411
|
+
* `repeat` 를 몇 개로 펼치나.
|
|
412
|
+
*
|
|
413
|
+
* **기준 상자를 한 칸씩 채운다.** 저작자는 **단위 하나**를 그리고, 런타임이 그 축의
|
|
414
|
+
* 길이를 채운다. 3D 도구의 배열 변형이 "길이에 맞추기" 로 하는 일과 같다.
|
|
415
|
+
*
|
|
416
|
+
* 개수 = floor(기준 상자의 그 축 길이 × 인스턴스 배율 ÷ 한 칸)
|
|
417
|
+
*
|
|
418
|
+
* ## 한 칸은 **중심에서 다음 중심까지**다
|
|
419
|
+
*
|
|
420
|
+
* 부품 크기와 무관하다. 전에는 `부품 크기 + 틈` 으로 셌는데, 그러면 부품을 굵게 하거나
|
|
421
|
+
* 돌릴 때마다 줄 전체가 다시 깔린다. 롤러를 30° 기울였더니 축 방향 경계상자가 96 에서
|
|
422
|
+
* 343 으로 늘어 개수가 16 에서 6 으로 무너졌다. 기울어진 롤러 둘은 빗살처럼 나란히
|
|
423
|
+
* 놓이므로 그렇게 벌릴 이유가 없는데도 그랬다.
|
|
424
|
+
*
|
|
425
|
+
* 이제 기울여도 개수가 그대로다. **기울인 채로 바짝 붙여 까는 것**이 표현된다.
|
|
426
|
+
*
|
|
427
|
+
* ## 왜 부품 크기가 아니라 기준 상자를 채우나
|
|
428
|
+
*
|
|
429
|
+
* 전에는 "그 부품이 `scale` 이었다면 차지했을 만큼" 을 채웠다. 지름 96 짜리 롤러는
|
|
430
|
+
* 컨베이어를 3 배로 늘려도 288 밖에 안 되어 롤러가 한두 개 나온다. 2400 짜리 컨베이어에
|
|
431
|
+
* 롤러 하나는 컨베이어가 아니다.
|
|
432
|
+
*
|
|
433
|
+
* 롤러는 일정한 간격으로 전 구간에 깔린다. 길이가 두 배면 롤러도 두 배다.
|
|
434
|
+
*/
|
|
435
|
+
export function repeatPlan(member, scale, base) {
|
|
436
|
+
if (member.sizing !== 'repeat' || !member.repeat)
|
|
437
|
+
return null;
|
|
438
|
+
const axis = member.repeat.axis;
|
|
439
|
+
const pitch = member.repeat.pitch;
|
|
440
|
+
if (!(Number.isFinite(pitch) && pitch > 0))
|
|
441
|
+
return null;
|
|
442
|
+
/*
|
|
443
|
+
**줄이 늘어나나 커지나.**
|
|
444
|
+
|
|
445
|
+
같은 「반복」이 두 가지다. 컨베이어의 롤러는 길어지면 개수가 늘고 한 칸 간격은
|
|
446
|
+
그대로다. 셀트레이의 셀은 커지면 셀이 커지고 개수는 그대로다 — 개수는 그 트레이가
|
|
447
|
+
몇 셀짜리냐이지 화면에 얼마나 크게 그렸느냐가 아니다.
|
|
448
|
+
|
|
449
|
+
그 갈림을 이 축의 앵커가 말한다. `scale` 이면 저작한 상자만으로 세고, 늘어나는
|
|
450
|
+
일은 부모의 배율이 한다(그릇이 배율을 되돌리지 않으므로 간격도 크기도 함께 큰다).
|
|
451
|
+
*/
|
|
452
|
+
const spreads = anchorOf(member, base, axis) !== 'scale';
|
|
453
|
+
const factor = spreads && Number.isFinite(scale[axis]) && scale[axis] > 0 ? scale[axis] : 1;
|
|
454
|
+
const room = (Number.isFinite(base[axis]) && base[axis] > 0 ? base[axis] : pitch) * factor;
|
|
455
|
+
const count = Math.max(1, Math.min(REPEAT_LIMIT, Math.floor(room / pitch)));
|
|
456
|
+
return { axis, count, pitch };
|
|
457
|
+
}
|
|
458
|
+
/**
|
|
459
|
+
* 한 부품이 펼쳐질 수 있는 최대 개수.
|
|
460
|
+
*
|
|
461
|
+
* 복제본 하나가 draw call 하나다. 인스턴스를 아주 크게 늘리면 개수가 끝없이 늘어 한
|
|
462
|
+
* 자산이 프레임을 다 먹는다. 그 지점에서는 이미 낱개를 셀 수 없으므로 더 늘려도 보이는
|
|
463
|
+
* 것이 달라지지 않는다.
|
|
464
|
+
*/
|
|
465
|
+
export const REPEAT_LIMIT = 100;
|
|
466
|
+
/**
|
|
467
|
+
* 복제본 하나의 자리 — 저작한 자리를 가운데 두고 양쪽으로 벌린다.
|
|
468
|
+
*
|
|
469
|
+
* 한쪽으로만 늘어놓으면 부품이 커질 때마다 한 방향으로 밀려서, 저작할 때 맞춰 둔 자리가
|
|
470
|
+
* 어긋난다. 가운데를 지키면 대칭으로 놓은 것들이 계속 대칭이다.
|
|
471
|
+
*/
|
|
472
|
+
export function repeatOffset(index, count, pitch) {
|
|
473
|
+
return (index - (count - 1) / 2) * pitch;
|
|
474
|
+
}
|
|
475
|
+
//# sourceMappingURL=sizing.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sizing.js","sourceRoot":"","sources":["../src/sizing.ts"],"names":[],"mappings":"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"}
|