@hatiolab/figure-model 0.4.1 → 0.4.2
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/asset-types.d.ts +6 -0
- package/dist/asset-types.d.ts.map +1 -1
- package/dist/asset-types.js.map +1 -1
- package/dist/authoring-actions.d.ts +30 -0
- package/dist/authoring-actions.d.ts.map +1 -1
- package/dist/authoring-actions.js +91 -8
- package/dist/authoring-actions.js.map +1 -1
- package/dist/capabilities.d.ts.map +1 -1
- package/dist/capabilities.js +71 -11
- package/dist/capabilities.js.map +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/kernel-version.d.ts +1 -1
- package/dist/kernel-version.js +1 -1
- package/dist/proposal.d.ts +1 -1
- package/dist/proposal.d.ts.map +1 -1
- package/dist/proposal.js +8 -0
- package/dist/proposal.js.map +1 -1
- package/dist/release-contract.d.ts +1 -1
- package/dist/release-contract.d.ts.map +1 -1
- package/dist/release-contract.js +27 -4
- package/dist/release-contract.js.map +1 -1
- package/dist/slot-layout.d.ts +212 -0
- package/dist/slot-layout.d.ts.map +1 -0
- package/dist/slot-layout.js +333 -0
- package/dist/slot-layout.js.map +1 -0
- package/dist/slot-places.d.ts +45 -0
- package/dist/slot-places.d.ts.map +1 -0
- package/dist/slot-places.js +40 -0
- package/dist/slot-places.js.map +1 -0
- package/docs/modeller-interaction-performance-2026-10-07.md +60 -0
- package/package.json +2 -1
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
export type LayoutIssueCode = 'TIERS_REQUIRED' | 'MOUNT_INVALID' | 'TIER_NUMBER_SEQUENCE' | 'ELEVATION_NOT_ASCENDING' | 'FINITE_NUMBER_REQUIRED' | 'POSITIVE_NUMBER_REQUIRED' | 'POSITIVE_INTEGER_REQUIRED' | 'ARRAY_REQUIRED' | 'OBJECT_REQUIRED' | 'AXIS_INVALID' | 'PATTERN_INVALID' | 'SLOT_NUMBER_SEQUENCE'
|
|
2
|
+
/** A value JSON would turn into null (params.value: NaN, Infinity, -Infinity). */
|
|
3
|
+
| 'NOT_PERSISTABLE';
|
|
4
|
+
/** A problem as a code, the path of the value, and parameters -- never a sentence. The screen words it. */
|
|
5
|
+
export interface LayoutIssue {
|
|
6
|
+
code: LayoutIssueCode;
|
|
7
|
+
/** Where the value is, e.g. 'tiers[0].layout.pitch'. Empty for the layout as a whole. */
|
|
8
|
+
path: string;
|
|
9
|
+
params?: Record<string, string | number>;
|
|
10
|
+
}
|
|
11
|
+
export declare function layoutIssue(code: LayoutIssueCode, path: string, params?: Record<string, string | number>): LayoutIssue;
|
|
12
|
+
/** How a holder carries what it holds: on top, inside, or hanging below. */
|
|
13
|
+
export type SlotMount = 'ON' | 'IN' | 'HANG';
|
|
14
|
+
export interface SlotLayout {
|
|
15
|
+
mount: SlotMount;
|
|
16
|
+
/** In tierNo order, bottom to top. */
|
|
17
|
+
tiers: SlotLayoutTier[];
|
|
18
|
+
}
|
|
19
|
+
export interface SlotLayoutTier {
|
|
20
|
+
/** From 1. */
|
|
21
|
+
tierNo: number;
|
|
22
|
+
/** The tier floor's height above the holder's floor -- not added to the tier below's. */
|
|
23
|
+
elevation: number;
|
|
24
|
+
layout: SlotPattern;
|
|
25
|
+
}
|
|
26
|
+
/** How the slots of one tier are arranged. */
|
|
27
|
+
export type SlotPattern = {
|
|
28
|
+
pattern: 'SINGLE';
|
|
29
|
+
slot: SlotSpec;
|
|
30
|
+
}
|
|
31
|
+
/** origin: which end of the axis slot 1 is at. MIN by default. */
|
|
32
|
+
| {
|
|
33
|
+
pattern: 'ROW';
|
|
34
|
+
count: number;
|
|
35
|
+
pitch: number;
|
|
36
|
+
axis: 'X' | 'Z';
|
|
37
|
+
origin?: 'MIN' | 'MAX';
|
|
38
|
+
slot: SlotSpec;
|
|
39
|
+
}
|
|
40
|
+
/** rows run along Z, columns along X. */
|
|
41
|
+
| {
|
|
42
|
+
pattern: 'GRID';
|
|
43
|
+
rows: number;
|
|
44
|
+
cols: number;
|
|
45
|
+
pitch: {
|
|
46
|
+
x: number;
|
|
47
|
+
z: number;
|
|
48
|
+
};
|
|
49
|
+
slot: SlotSpec;
|
|
50
|
+
order?: GridOrder;
|
|
51
|
+
origin?: GridOrigin;
|
|
52
|
+
} | {
|
|
53
|
+
pattern: 'CUSTOM';
|
|
54
|
+
slots: PatternSlot[];
|
|
55
|
+
};
|
|
56
|
+
/** The order GRID slots are numbered in. ROW_MAJOR by default. */
|
|
57
|
+
export type GridOrder = 'ROW_MAJOR' | 'COL_MAJOR' | 'SERPENTINE_ROW' | 'SERPENTINE_COL';
|
|
58
|
+
/** The corner GRID slot 1 is at. { x: 'MIN', z: 'MIN' } by default. */
|
|
59
|
+
export interface GridOrigin {
|
|
60
|
+
x: 'MIN' | 'MAX';
|
|
61
|
+
z: 'MIN' | 'MAX';
|
|
62
|
+
}
|
|
63
|
+
/** One slot's room and rules. Every slot of a SINGLE, ROW or GRID tier has the same. */
|
|
64
|
+
export interface SlotSpec {
|
|
65
|
+
/** The room a held thing may take: width along X, depth along Z, height along Y. */
|
|
66
|
+
allowed: {
|
|
67
|
+
width: number;
|
|
68
|
+
depth: number;
|
|
69
|
+
height: number;
|
|
70
|
+
};
|
|
71
|
+
/**
|
|
72
|
+
* The item types it takes. Left out: any type; an empty list: none. (A figure's declaration must name them --
|
|
73
|
+
* ADR-0087 decision 3; that is the figure's rule, checked where figures are compiled, not here.)
|
|
74
|
+
*/
|
|
75
|
+
accepts?: string[];
|
|
76
|
+
/** How many may be stacked in it. 1 when left out. */
|
|
77
|
+
stackLimit?: number;
|
|
78
|
+
/** Degrees about Y. */
|
|
79
|
+
rotation?: number;
|
|
80
|
+
}
|
|
81
|
+
/** A slot of a CUSTOM tier. */
|
|
82
|
+
export interface PatternSlot extends SlotSpec {
|
|
83
|
+
/** From 1 within the tier. */
|
|
84
|
+
slotNo: number;
|
|
85
|
+
/** For display (FRONT, REAR, L, R …). */
|
|
86
|
+
name?: string;
|
|
87
|
+
/** The slot's centre relative to the tier's centre. */
|
|
88
|
+
offset: {
|
|
89
|
+
x: number;
|
|
90
|
+
z: number;
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
export interface SlotAddress {
|
|
94
|
+
tier: number;
|
|
95
|
+
slot: number;
|
|
96
|
+
}
|
|
97
|
+
/** A slot found by its address. offset is from the tier's centre, elevation from the holder's floor. */
|
|
98
|
+
export interface ResolvedSlot {
|
|
99
|
+
tier: number;
|
|
100
|
+
slotNo: number;
|
|
101
|
+
name?: string;
|
|
102
|
+
elevation: number;
|
|
103
|
+
offset: {
|
|
104
|
+
x: number;
|
|
105
|
+
z: number;
|
|
106
|
+
};
|
|
107
|
+
allowed: {
|
|
108
|
+
width: number;
|
|
109
|
+
depth: number;
|
|
110
|
+
height: number;
|
|
111
|
+
};
|
|
112
|
+
accepts?: string[];
|
|
113
|
+
stackLimit: number;
|
|
114
|
+
rotation: number;
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Everything wrong with a layout; an empty list is a sound one. stackLimit may be Infinity (no limit); a layout that is
|
|
118
|
+
* to be stored as JSON is also checked with `persistenceIssues`.
|
|
119
|
+
*/
|
|
120
|
+
export declare function validateSlotLayout(layout: SlotLayout): LayoutIssue[];
|
|
121
|
+
/** Values JSON turns into null (NaN, Infinity): stored, they would come back as a broken layout. */
|
|
122
|
+
export declare function persistenceIssues(value: unknown, path?: string): LayoutIssue[];
|
|
123
|
+
export declare function slotCount(pattern: SlotPattern): number;
|
|
124
|
+
/** A GRID slot's number from its row r and column c (from 1), counted from the origin corner. */
|
|
125
|
+
export declare function gridSlotNo(rows: number, cols: number, r: number, c: number, order?: GridOrder): number;
|
|
126
|
+
/** The row and column of a GRID slot number -- the inverse of gridSlotNo. */
|
|
127
|
+
export declare function gridCellOf(rows: number, cols: number, slotNo: number, order?: GridOrder): {
|
|
128
|
+
r: number;
|
|
129
|
+
c: number;
|
|
130
|
+
};
|
|
131
|
+
export interface ResolveSlotOptions {
|
|
132
|
+
/** The stackLimit of a slot that names none. 1 by default; Infinity for a holder's unlimited default slot. */
|
|
133
|
+
defaultStackLimit?: number;
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* The slot at an address, or null when the tier or the slot is not there. ROW and GRID slots are worked out:
|
|
137
|
+
* ROW centre = ((n - 1) - (count - 1) / 2) × pitch, negated when origin is MAX
|
|
138
|
+
* GRID centre = the row and column the order gives, x = (c - 1 - (cols - 1)/2) × pitch.x,
|
|
139
|
+
* z = (r - 1 - (rows - 1)/2) × pitch.z, each negated when its origin is MAX
|
|
140
|
+
*/
|
|
141
|
+
export declare function resolveSlot(layout: SlotLayout, address: SlotAddress, options?: ResolveSlotOptions): ResolvedSlot | null;
|
|
142
|
+
/** A slot's logical id. */
|
|
143
|
+
export declare function slotIdOf(address: SlotAddress): string;
|
|
144
|
+
/** The address a slot id names, or null when it is not one. */
|
|
145
|
+
export declare function addressOfSlotId(slotId: unknown): SlotAddress | null;
|
|
146
|
+
/** Every address of a layout, tier by tier. For a big GRID, resolve only the addresses you need. */
|
|
147
|
+
export declare function slotAddresses(layout: SlotLayout): Generator<SlotAddress>;
|
|
148
|
+
/** An item's size: width along X, depth along Z, height along Y -- in the layout's unit. */
|
|
149
|
+
export interface ItemDims {
|
|
150
|
+
width: number;
|
|
151
|
+
depth: number;
|
|
152
|
+
height: number;
|
|
153
|
+
}
|
|
154
|
+
/** Where an item sits, in the holder's coordinates: its centre, its turn about Y in degrees, and one uniform scale. */
|
|
155
|
+
export interface SeatTransform {
|
|
156
|
+
position: {
|
|
157
|
+
x: number;
|
|
158
|
+
y: number;
|
|
159
|
+
z: number;
|
|
160
|
+
};
|
|
161
|
+
rotation: number;
|
|
162
|
+
scale: number;
|
|
163
|
+
}
|
|
164
|
+
export declare const DEFAULT_SEAT_MARGIN = 0.05;
|
|
165
|
+
/** The X and Z extent of an item turned by `rotation` degrees. */
|
|
166
|
+
export declare function rotatedFootprint(dims: ItemDims, rotation: number): {
|
|
167
|
+
width: number;
|
|
168
|
+
depth: number;
|
|
169
|
+
};
|
|
170
|
+
/**
|
|
171
|
+
* Where an item sits in a slot: shrunk to fit the slot's width and depth (by its turned extent, never enlarged), on top
|
|
172
|
+
* of `belowHeight` -- the shown heights (height × scale) of what is stacked under it. `margin` is room left only for
|
|
173
|
+
* showing (0 ≤ margin < 1); whether it fits is judged elsewhere, at full size. Null when a size or value is unusable --
|
|
174
|
+
* never NaN or Infinity.
|
|
175
|
+
*/
|
|
176
|
+
export declare function seatTransform(dims: ItemDims, slot: ResolvedSlot, mount: SlotMount, belowHeight?: number, margin?: number): SeatTransform | null;
|
|
177
|
+
/** Where each of a slot's stacked items sits, bottom first. An item of unknown size is null and adds no height. */
|
|
178
|
+
export declare function stackSeatTransforms(stack: (ItemDims | null | undefined)[], slot: ResolvedSlot, mount: SlotMount, margin?: number): (SeatTransform | null)[];
|
|
179
|
+
/** A slot anchor's place in the holder: the slot's offset and the tier's elevation, nothing else. */
|
|
180
|
+
export declare function slotAnchorPosition(slot: ResolvedSlot): {
|
|
181
|
+
x: number;
|
|
182
|
+
y: number;
|
|
183
|
+
z: number;
|
|
184
|
+
};
|
|
185
|
+
/**
|
|
186
|
+
* Where an item sits when it hangs off a slot anchor: only the stack height, half its height, scale and turn; x and z are
|
|
187
|
+
* 0 because the anchor already has the offset and elevation.
|
|
188
|
+
* slotAnchorPosition(slot) + seatInAnchor(...).position = seatTransform(...).position
|
|
189
|
+
*/
|
|
190
|
+
export declare function seatInAnchor(dims: ItemDims, slot: ResolvedSlot, mount: SlotMount, belowHeight?: number, margin?: number): SeatTransform | null;
|
|
191
|
+
export type FitVerdict = 'OK' | 'NG' | 'UNKNOWN';
|
|
192
|
+
export type FitReason = 'SLOT_NOT_FOUND' | 'TYPE_NOT_ACCEPTED' | 'WIDTH_EXCEEDED' | 'DEPTH_EXCEEDED' | 'HEIGHT_EXCEEDED' | 'STACK_LIMIT_EXCEEDED' | 'SPEC_UNKNOWN';
|
|
193
|
+
export interface FitCandidate {
|
|
194
|
+
type?: string;
|
|
195
|
+
/** Left out when the size is not known. */
|
|
196
|
+
dims?: ItemDims | null;
|
|
197
|
+
}
|
|
198
|
+
export interface FitResult {
|
|
199
|
+
verdict: FitVerdict;
|
|
200
|
+
reasons: FitReason[];
|
|
201
|
+
}
|
|
202
|
+
export interface FitOptions {
|
|
203
|
+
/** Applied to both sides before types are compared. The type as it is by default. */
|
|
204
|
+
normalizeType?: (type: unknown) => string;
|
|
205
|
+
}
|
|
206
|
+
/**
|
|
207
|
+
* Whether one more item fits in a slot that already holds `occupants`, at full size. The count limit and the height
|
|
208
|
+
* limit are separate checks. accepts left out takes any type; an empty list takes none. UNKNOWN when a type or a size
|
|
209
|
+
* needed to judge is not known.
|
|
210
|
+
*/
|
|
211
|
+
export declare function judgeItemFit(slot: ResolvedSlot | null, candidate: FitCandidate, occupants?: FitCandidate[], options?: FitOptions): FitResult;
|
|
212
|
+
//# sourceMappingURL=slot-layout.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"slot-layout.d.ts","sourceRoot":"","sources":["../src/slot-layout.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,333 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Slot layouts (ADR-0118): a holder's tiers, the slots on each tier, how slots are numbered, where an item sits in a
|
|
3
|
+
* slot, and whether it fits. Pure computation; nothing here knows a scene, a graph or a component.
|
|
4
|
+
*
|
|
5
|
+
* A holder has one or more tiers; each tier has its own arrangement (SINGLE, ROW, GRID or CUSTOM). A slot's address is
|
|
6
|
+
* (tier, slot), both counted from 1, and slot numbers restart on every tier. ROW and GRID slots are not stored: they are
|
|
7
|
+
* worked out from the rule, so thousands of slots are one rule. A slot's id is `t{tier}_s{slot}` -- a logical id, not
|
|
8
|
+
* the name of a node in any 3D asset.
|
|
9
|
+
*
|
|
10
|
+
* Coordinates are the holder's own: X and Z put a slot's centre relative to the tier's centre, Y is the tier floor's
|
|
11
|
+
* height above the holder's floor. Lengths are in whatever unit the layout is written in; nothing here converts them.
|
|
12
|
+
* Rotations are in degrees about Y.
|
|
13
|
+
*/
|
|
14
|
+
export function layoutIssue(code, path, params) {
|
|
15
|
+
return params ? { code, path, params } : { code, path };
|
|
16
|
+
}
|
|
17
|
+
/* ── checking a layout ───────────────────────────────────────────────────── */
|
|
18
|
+
const isFiniteNumber = (v) => typeof v === 'number' && Number.isFinite(v);
|
|
19
|
+
const isPositive = (v) => isFiniteNumber(v) && v > 0;
|
|
20
|
+
const isPositiveInt = (v) => Number.isSafeInteger(v) && v > 0;
|
|
21
|
+
function checkSpec(spec, path, issues) {
|
|
22
|
+
const a = spec?.allowed;
|
|
23
|
+
if (!a || typeof a !== 'object')
|
|
24
|
+
issues.push(layoutIssue('OBJECT_REQUIRED', `${path}.allowed`));
|
|
25
|
+
else
|
|
26
|
+
for (const k of ['width', 'depth', 'height'])
|
|
27
|
+
if (!isPositive(a[k]))
|
|
28
|
+
issues.push(layoutIssue('POSITIVE_NUMBER_REQUIRED', `${path}.allowed.${k}`));
|
|
29
|
+
if (spec?.stackLimit !== undefined && !isPositiveInt(spec.stackLimit) && spec.stackLimit !== Infinity)
|
|
30
|
+
issues.push(layoutIssue('POSITIVE_INTEGER_REQUIRED', `${path}.stackLimit`));
|
|
31
|
+
if (spec?.rotation !== undefined && !isFiniteNumber(spec.rotation))
|
|
32
|
+
issues.push(layoutIssue('FINITE_NUMBER_REQUIRED', `${path}.rotation`));
|
|
33
|
+
if (spec?.accepts !== undefined && !Array.isArray(spec.accepts))
|
|
34
|
+
issues.push(layoutIssue('ARRAY_REQUIRED', `${path}.accepts`));
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Everything wrong with a layout; an empty list is a sound one. stackLimit may be Infinity (no limit); a layout that is
|
|
38
|
+
* to be stored as JSON is also checked with `persistenceIssues`.
|
|
39
|
+
*/
|
|
40
|
+
export function validateSlotLayout(layout) {
|
|
41
|
+
const issues = [];
|
|
42
|
+
if (!layout || !Array.isArray(layout.tiers) || layout.tiers.length === 0)
|
|
43
|
+
return [layoutIssue('TIERS_REQUIRED', 'tiers')];
|
|
44
|
+
if (!['ON', 'IN', 'HANG'].includes(layout.mount))
|
|
45
|
+
issues.push(layoutIssue('MOUNT_INVALID', 'mount'));
|
|
46
|
+
layout.tiers.forEach((tier, i) => {
|
|
47
|
+
const path = `tiers[${i}]`;
|
|
48
|
+
if (!tier || typeof tier !== 'object') {
|
|
49
|
+
issues.push(layoutIssue('OBJECT_REQUIRED', path));
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
if (tier.tierNo !== i + 1)
|
|
53
|
+
issues.push(layoutIssue('TIER_NUMBER_SEQUENCE', `${path}.tierNo`));
|
|
54
|
+
if (!isFiniteNumber(tier.elevation))
|
|
55
|
+
issues.push(layoutIssue('FINITE_NUMBER_REQUIRED', `${path}.elevation`));
|
|
56
|
+
else if (i > 0 && isFiniteNumber(layout.tiers[i - 1]?.elevation) && tier.elevation <= layout.tiers[i - 1].elevation)
|
|
57
|
+
issues.push(layoutIssue('ELEVATION_NOT_ASCENDING', `${path}.elevation`));
|
|
58
|
+
const l = tier.layout;
|
|
59
|
+
switch (l?.pattern) {
|
|
60
|
+
case 'SINGLE':
|
|
61
|
+
checkSpec(l.slot, `${path}.layout.slot`, issues);
|
|
62
|
+
break;
|
|
63
|
+
case 'ROW':
|
|
64
|
+
if (!isPositiveInt(l.count))
|
|
65
|
+
issues.push(layoutIssue('POSITIVE_INTEGER_REQUIRED', `${path}.layout.count`));
|
|
66
|
+
if (!isPositive(l.pitch))
|
|
67
|
+
issues.push(layoutIssue('POSITIVE_NUMBER_REQUIRED', `${path}.layout.pitch`));
|
|
68
|
+
if (l.axis !== 'X' && l.axis !== 'Z')
|
|
69
|
+
issues.push(layoutIssue('AXIS_INVALID', `${path}.layout.axis`));
|
|
70
|
+
checkSpec(l.slot, `${path}.layout.slot`, issues);
|
|
71
|
+
break;
|
|
72
|
+
case 'GRID':
|
|
73
|
+
if (!isPositiveInt(l.rows))
|
|
74
|
+
issues.push(layoutIssue('POSITIVE_INTEGER_REQUIRED', `${path}.layout.rows`));
|
|
75
|
+
if (!isPositiveInt(l.cols))
|
|
76
|
+
issues.push(layoutIssue('POSITIVE_INTEGER_REQUIRED', `${path}.layout.cols`));
|
|
77
|
+
if (!isPositive(l.pitch?.x))
|
|
78
|
+
issues.push(layoutIssue('POSITIVE_NUMBER_REQUIRED', `${path}.layout.pitch.x`));
|
|
79
|
+
if (!isPositive(l.pitch?.z))
|
|
80
|
+
issues.push(layoutIssue('POSITIVE_NUMBER_REQUIRED', `${path}.layout.pitch.z`));
|
|
81
|
+
checkSpec(l.slot, `${path}.layout.slot`, issues);
|
|
82
|
+
break;
|
|
83
|
+
case 'CUSTOM': {
|
|
84
|
+
const slots = Array.isArray(l.slots) ? l.slots : [];
|
|
85
|
+
const nos = slots.map(s => s?.slotNo).sort((a, b) => a - b);
|
|
86
|
+
if (!nos.length || nos.some((n, k) => n !== k + 1))
|
|
87
|
+
issues.push(layoutIssue('SLOT_NUMBER_SEQUENCE', `${path}.layout.slots`));
|
|
88
|
+
slots.forEach((s, k) => {
|
|
89
|
+
if (!isFiniteNumber(s?.offset?.x) || !isFiniteNumber(s?.offset?.z))
|
|
90
|
+
issues.push(layoutIssue('FINITE_NUMBER_REQUIRED', `${path}.layout.slots[${k}].offset`));
|
|
91
|
+
checkSpec(s, `${path}.layout.slots[${k}]`, issues);
|
|
92
|
+
});
|
|
93
|
+
break;
|
|
94
|
+
}
|
|
95
|
+
default:
|
|
96
|
+
issues.push(layoutIssue('PATTERN_INVALID', `${path}.layout.pattern`));
|
|
97
|
+
}
|
|
98
|
+
});
|
|
99
|
+
return issues;
|
|
100
|
+
}
|
|
101
|
+
/** Values JSON turns into null (NaN, Infinity): stored, they would come back as a broken layout. */
|
|
102
|
+
export function persistenceIssues(value, path = '') {
|
|
103
|
+
const issues = [];
|
|
104
|
+
const walk = (v, p) => {
|
|
105
|
+
if (typeof v === 'number' && !Number.isFinite(v))
|
|
106
|
+
issues.push(layoutIssue('NOT_PERSISTABLE', p, { value: String(v) }));
|
|
107
|
+
else if (Array.isArray(v))
|
|
108
|
+
v.forEach((x, i) => walk(x, `${p}[${i}]`));
|
|
109
|
+
else if (v && typeof v === 'object')
|
|
110
|
+
for (const [k, x] of Object.entries(v))
|
|
111
|
+
walk(x, p ? `${p}.${k}` : k);
|
|
112
|
+
};
|
|
113
|
+
walk(value, path);
|
|
114
|
+
return issues;
|
|
115
|
+
}
|
|
116
|
+
/* ── numbering ───────────────────────────────────────────────────────────── */
|
|
117
|
+
export function slotCount(pattern) {
|
|
118
|
+
switch (pattern.pattern) {
|
|
119
|
+
case 'SINGLE':
|
|
120
|
+
return 1;
|
|
121
|
+
case 'ROW':
|
|
122
|
+
return pattern.count;
|
|
123
|
+
case 'GRID':
|
|
124
|
+
return pattern.rows * pattern.cols;
|
|
125
|
+
case 'CUSTOM':
|
|
126
|
+
return pattern.slots.length;
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
/** A GRID slot's number from its row r and column c (from 1), counted from the origin corner. */
|
|
130
|
+
export function gridSlotNo(rows, cols, r, c, order = 'ROW_MAJOR') {
|
|
131
|
+
switch (order) {
|
|
132
|
+
case 'ROW_MAJOR':
|
|
133
|
+
return (r - 1) * cols + c;
|
|
134
|
+
case 'COL_MAJOR':
|
|
135
|
+
return (c - 1) * rows + r;
|
|
136
|
+
case 'SERPENTINE_ROW':
|
|
137
|
+
return (r - 1) * cols + (r % 2 === 1 ? c : cols - c + 1);
|
|
138
|
+
case 'SERPENTINE_COL':
|
|
139
|
+
return (c - 1) * rows + (c % 2 === 1 ? r : rows - r + 1);
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
/** The row and column of a GRID slot number -- the inverse of gridSlotNo. */
|
|
143
|
+
export function gridCellOf(rows, cols, slotNo, order = 'ROW_MAJOR') {
|
|
144
|
+
const i = slotNo - 1;
|
|
145
|
+
switch (order) {
|
|
146
|
+
case 'ROW_MAJOR':
|
|
147
|
+
return { r: Math.floor(i / cols) + 1, c: (i % cols) + 1 };
|
|
148
|
+
case 'COL_MAJOR':
|
|
149
|
+
return { r: (i % rows) + 1, c: Math.floor(i / rows) + 1 };
|
|
150
|
+
case 'SERPENTINE_ROW': {
|
|
151
|
+
const r = Math.floor(i / cols) + 1;
|
|
152
|
+
const k = (i % cols) + 1;
|
|
153
|
+
return { r, c: r % 2 === 1 ? k : cols - k + 1 };
|
|
154
|
+
}
|
|
155
|
+
case 'SERPENTINE_COL': {
|
|
156
|
+
const c = Math.floor(i / rows) + 1;
|
|
157
|
+
const k = (i % rows) + 1;
|
|
158
|
+
return { r: c % 2 === 1 ? k : rows - k + 1, c };
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
/** Flips a sign without making -0. */
|
|
163
|
+
const flip = (v, max) => (max && v !== 0 ? -v : v);
|
|
164
|
+
/**
|
|
165
|
+
* The slot at an address, or null when the tier or the slot is not there. ROW and GRID slots are worked out:
|
|
166
|
+
* ROW centre = ((n - 1) - (count - 1) / 2) × pitch, negated when origin is MAX
|
|
167
|
+
* GRID centre = the row and column the order gives, x = (c - 1 - (cols - 1)/2) × pitch.x,
|
|
168
|
+
* z = (r - 1 - (rows - 1)/2) × pitch.z, each negated when its origin is MAX
|
|
169
|
+
*/
|
|
170
|
+
export function resolveSlot(layout, address, options = {}) {
|
|
171
|
+
const tier = layout?.tiers?.find(t => t?.tierNo === address?.tier);
|
|
172
|
+
if (!tier || !isPositiveInt(address.slot) || address.slot > slotCount(tier.layout))
|
|
173
|
+
return null;
|
|
174
|
+
const l = tier.layout;
|
|
175
|
+
let spec;
|
|
176
|
+
let offset;
|
|
177
|
+
let name;
|
|
178
|
+
switch (l.pattern) {
|
|
179
|
+
case 'SINGLE':
|
|
180
|
+
spec = l.slot;
|
|
181
|
+
offset = { x: 0, z: 0 };
|
|
182
|
+
break;
|
|
183
|
+
case 'ROW': {
|
|
184
|
+
const v = flip((address.slot - 1 - (l.count - 1) / 2) * l.pitch, l.origin === 'MAX');
|
|
185
|
+
spec = l.slot;
|
|
186
|
+
offset = l.axis === 'X' ? { x: v, z: 0 } : { x: 0, z: v };
|
|
187
|
+
break;
|
|
188
|
+
}
|
|
189
|
+
case 'GRID': {
|
|
190
|
+
const { r, c } = gridCellOf(l.rows, l.cols, address.slot, l.order);
|
|
191
|
+
const origin = l.origin ?? { x: 'MIN', z: 'MIN' };
|
|
192
|
+
spec = l.slot;
|
|
193
|
+
offset = {
|
|
194
|
+
x: flip((c - 1 - (l.cols - 1) / 2) * l.pitch.x, origin.x === 'MAX'),
|
|
195
|
+
z: flip((r - 1 - (l.rows - 1) / 2) * l.pitch.z, origin.z === 'MAX')
|
|
196
|
+
};
|
|
197
|
+
break;
|
|
198
|
+
}
|
|
199
|
+
case 'CUSTOM': {
|
|
200
|
+
const s = l.slots.find(s => s.slotNo === address.slot);
|
|
201
|
+
if (!s)
|
|
202
|
+
return null;
|
|
203
|
+
spec = s;
|
|
204
|
+
offset = { ...s.offset };
|
|
205
|
+
name = s.name;
|
|
206
|
+
break;
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
return {
|
|
210
|
+
tier: tier.tierNo,
|
|
211
|
+
slotNo: address.slot,
|
|
212
|
+
name,
|
|
213
|
+
elevation: tier.elevation,
|
|
214
|
+
offset,
|
|
215
|
+
allowed: { ...spec.allowed },
|
|
216
|
+
accepts: spec.accepts ? [...spec.accepts] : undefined,
|
|
217
|
+
stackLimit: spec.stackLimit ?? options.defaultStackLimit ?? 1,
|
|
218
|
+
rotation: spec.rotation ?? 0
|
|
219
|
+
};
|
|
220
|
+
}
|
|
221
|
+
/* ── slot ids ────────────────────────────────────────────────────────────── */
|
|
222
|
+
/** A slot's logical id. */
|
|
223
|
+
export function slotIdOf(address) {
|
|
224
|
+
return `t${address.tier}_s${address.slot}`;
|
|
225
|
+
}
|
|
226
|
+
/** The address a slot id names, or null when it is not one. */
|
|
227
|
+
export function addressOfSlotId(slotId) {
|
|
228
|
+
const m = typeof slotId === 'string' ? /^t(\d+)_s(\d+)$/.exec(slotId) : null;
|
|
229
|
+
return m ? { tier: Number(m[1]), slot: Number(m[2]) } : null;
|
|
230
|
+
}
|
|
231
|
+
/** Every address of a layout, tier by tier. For a big GRID, resolve only the addresses you need. */
|
|
232
|
+
export function* slotAddresses(layout) {
|
|
233
|
+
for (const tier of layout?.tiers ?? [])
|
|
234
|
+
for (let slot = 1; slot <= slotCount(tier.layout); slot++)
|
|
235
|
+
yield { tier: tier.tierNo, slot };
|
|
236
|
+
}
|
|
237
|
+
export const DEFAULT_SEAT_MARGIN = 0.05;
|
|
238
|
+
const knownDims = (d) => !!d && isPositive(d.width) && isPositive(d.depth) && isPositive(d.height);
|
|
239
|
+
/** The X and Z extent of an item turned by `rotation` degrees. */
|
|
240
|
+
export function rotatedFootprint(dims, rotation) {
|
|
241
|
+
const rad = (rotation * Math.PI) / 180;
|
|
242
|
+
const c = Math.abs(Math.cos(rad));
|
|
243
|
+
const s = Math.abs(Math.sin(rad));
|
|
244
|
+
// clears the 6e-17 left at multiples of 90°
|
|
245
|
+
const clean = (v) => Math.round(v * 1e9) / 1e9;
|
|
246
|
+
return { width: clean(dims.width * c + dims.depth * s), depth: clean(dims.width * s + dims.depth * c) };
|
|
247
|
+
}
|
|
248
|
+
/**
|
|
249
|
+
* Where an item sits in a slot: shrunk to fit the slot's width and depth (by its turned extent, never enlarged), on top
|
|
250
|
+
* of `belowHeight` -- the shown heights (height × scale) of what is stacked under it. `margin` is room left only for
|
|
251
|
+
* showing (0 ≤ margin < 1); whether it fits is judged elsewhere, at full size. Null when a size or value is unusable --
|
|
252
|
+
* never NaN or Infinity.
|
|
253
|
+
*/
|
|
254
|
+
export function seatTransform(dims, slot, mount, belowHeight = 0, margin = DEFAULT_SEAT_MARGIN) {
|
|
255
|
+
if (!knownDims(dims))
|
|
256
|
+
return null;
|
|
257
|
+
if (!isFiniteNumber(belowHeight) || !isFiniteNumber(margin) || margin < 0 || margin >= 1)
|
|
258
|
+
return null;
|
|
259
|
+
const fp = rotatedFootprint(dims, slot.rotation);
|
|
260
|
+
const scale = Math.min(1, Math.min(slot.allowed.width / fp.width, slot.allowed.depth / fp.depth) * (1 - margin));
|
|
261
|
+
const h = dims.height * scale;
|
|
262
|
+
const dir = mount === 'HANG' ? -1 : 1;
|
|
263
|
+
const y = slot.elevation + dir * (belowHeight + h / 2);
|
|
264
|
+
return { position: { x: slot.offset.x, y, z: slot.offset.z }, rotation: slot.rotation, scale };
|
|
265
|
+
}
|
|
266
|
+
/** Where each of a slot's stacked items sits, bottom first. An item of unknown size is null and adds no height. */
|
|
267
|
+
export function stackSeatTransforms(stack, slot, mount, margin = DEFAULT_SEAT_MARGIN) {
|
|
268
|
+
let below = 0;
|
|
269
|
+
return stack.map(dims => {
|
|
270
|
+
const t = dims ? seatTransform(dims, slot, mount, below, margin) : null;
|
|
271
|
+
if (t)
|
|
272
|
+
below += dims.height * t.scale;
|
|
273
|
+
return t;
|
|
274
|
+
});
|
|
275
|
+
}
|
|
276
|
+
/** A slot anchor's place in the holder: the slot's offset and the tier's elevation, nothing else. */
|
|
277
|
+
export function slotAnchorPosition(slot) {
|
|
278
|
+
return { x: slot.offset.x, y: slot.elevation, z: slot.offset.z };
|
|
279
|
+
}
|
|
280
|
+
/**
|
|
281
|
+
* Where an item sits when it hangs off a slot anchor: only the stack height, half its height, scale and turn; x and z are
|
|
282
|
+
* 0 because the anchor already has the offset and elevation.
|
|
283
|
+
* slotAnchorPosition(slot) + seatInAnchor(...).position = seatTransform(...).position
|
|
284
|
+
*/
|
|
285
|
+
export function seatInAnchor(dims, slot, mount, belowHeight = 0, margin = DEFAULT_SEAT_MARGIN) {
|
|
286
|
+
const t = seatTransform(dims, slot, mount, belowHeight, margin);
|
|
287
|
+
if (!t)
|
|
288
|
+
return null;
|
|
289
|
+
return { position: { x: 0, y: t.position.y - slot.elevation, z: 0 }, rotation: t.rotation, scale: t.scale };
|
|
290
|
+
}
|
|
291
|
+
/**
|
|
292
|
+
* Whether one more item fits in a slot that already holds `occupants`, at full size. The count limit and the height
|
|
293
|
+
* limit are separate checks. accepts left out takes any type; an empty list takes none. UNKNOWN when a type or a size
|
|
294
|
+
* needed to judge is not known.
|
|
295
|
+
*/
|
|
296
|
+
export function judgeItemFit(slot, candidate, occupants = [], options = {}) {
|
|
297
|
+
if (!slot)
|
|
298
|
+
return { verdict: 'NG', reasons: ['SLOT_NOT_FOUND'] };
|
|
299
|
+
const norm = options.normalizeType ?? ((t) => (t === undefined || t === null ? '' : String(t)));
|
|
300
|
+
const reasons = [];
|
|
301
|
+
let unknown = false;
|
|
302
|
+
if (slot.accepts) {
|
|
303
|
+
const type = norm(candidate.type);
|
|
304
|
+
if (!type)
|
|
305
|
+
unknown = true;
|
|
306
|
+
else if (!slot.accepts.map(norm).includes(type))
|
|
307
|
+
reasons.push('TYPE_NOT_ACCEPTED');
|
|
308
|
+
}
|
|
309
|
+
if (occupants.length + 1 > slot.stackLimit)
|
|
310
|
+
reasons.push('STACK_LIMIT_EXCEEDED');
|
|
311
|
+
if (!knownDims(candidate.dims))
|
|
312
|
+
unknown = true;
|
|
313
|
+
else {
|
|
314
|
+
const fp = rotatedFootprint(candidate.dims, slot.rotation);
|
|
315
|
+
if (fp.width > slot.allowed.width)
|
|
316
|
+
reasons.push('WIDTH_EXCEEDED');
|
|
317
|
+
if (fp.depth > slot.allowed.depth)
|
|
318
|
+
reasons.push('DEPTH_EXCEEDED');
|
|
319
|
+
if (occupants.every(o => knownDims(o.dims))) {
|
|
320
|
+
const total = occupants.reduce((sum, o) => sum + o.dims.height, candidate.dims.height);
|
|
321
|
+
if (total > slot.allowed.height)
|
|
322
|
+
reasons.push('HEIGHT_EXCEEDED');
|
|
323
|
+
}
|
|
324
|
+
else
|
|
325
|
+
unknown = true;
|
|
326
|
+
}
|
|
327
|
+
if (reasons.length)
|
|
328
|
+
return { verdict: 'NG', reasons: unknown ? [...reasons, 'SPEC_UNKNOWN'] : reasons };
|
|
329
|
+
if (unknown)
|
|
330
|
+
return { verdict: 'UNKNOWN', reasons: ['SPEC_UNKNOWN'] };
|
|
331
|
+
return { verdict: 'OK', reasons: [] };
|
|
332
|
+
}
|
|
333
|
+
//# sourceMappingURL=slot-layout.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"slot-layout.js","sourceRoot":"","sources":["../src/slot-layout.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import type { FigureSurfaceReference } from './asset-types.ts';
|
|
2
|
+
import { type SlotLayout, type SlotMount } from './slot-layout.ts';
|
|
3
|
+
export interface FigureSlotLayoutDeclaration {
|
|
4
|
+
label: string;
|
|
5
|
+
role: 'seat' | 'grip';
|
|
6
|
+
/** The frame of the face the layout sits on -- the same rule as a binding's frame. */
|
|
7
|
+
frame: string;
|
|
8
|
+
/** The face the layout sits on. Its slots are laid out in the part's X and Z; tiers rise along its Y. */
|
|
9
|
+
pose: FigureSurfaceReference;
|
|
10
|
+
/** Every slot must name the types it takes (ADR-0087 decision 3). */
|
|
11
|
+
layout: SlotLayout;
|
|
12
|
+
}
|
|
13
|
+
/** One slot unfolded from a layout: a place like a binding, plus where on the face it is. */
|
|
14
|
+
export interface FigureSlotPlace {
|
|
15
|
+
id: string;
|
|
16
|
+
label: string;
|
|
17
|
+
role: 'seat' | 'grip';
|
|
18
|
+
frame: string;
|
|
19
|
+
pose: FigureSurfaceReference;
|
|
20
|
+
accepts: string[];
|
|
21
|
+
/** How many it holds at once: the slot's stackLimit. */
|
|
22
|
+
capacity: number;
|
|
23
|
+
tier: number;
|
|
24
|
+
slot: number;
|
|
25
|
+
name?: string;
|
|
26
|
+
/** The slot's centre on the face, in the part's X and Z. */
|
|
27
|
+
offset: {
|
|
28
|
+
x: number;
|
|
29
|
+
z: number;
|
|
30
|
+
};
|
|
31
|
+
/** The tier floor's height above the face, along the part's Y (below it for HANG). */
|
|
32
|
+
elevation: number;
|
|
33
|
+
/** Degrees about Y. */
|
|
34
|
+
rotation: number;
|
|
35
|
+
mount: SlotMount;
|
|
36
|
+
/** The room a held thing may take: width along X, height along Y, depth along Z. */
|
|
37
|
+
allowed: {
|
|
38
|
+
width: number;
|
|
39
|
+
depth: number;
|
|
40
|
+
height: number;
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
/** The places a declaration unfolds into, tier by tier and slot by slot. None when there is no declaration. */
|
|
44
|
+
export declare function figureSlotPlacesOf(declaration: FigureSlotLayoutDeclaration | undefined): FigureSlotPlace[];
|
|
45
|
+
//# sourceMappingURL=slot-places.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"slot-places.d.ts","sourceRoot":"","sources":["../src/slot-places.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,kBAAkB,CAAA;AAC9D,OAAO,EAAwC,KAAK,UAAU,EAAE,KAAK,SAAS,EAAE,MAAM,kBAAkB,CAAA;AAExG,MAAM,WAAW,2BAA2B;IAC1C,KAAK,EAAE,MAAM,CAAA;IACb,IAAI,EAAE,MAAM,GAAG,MAAM,CAAA;IACrB,sFAAsF;IACtF,KAAK,EAAE,MAAM,CAAA;IACb,yGAAyG;IACzG,IAAI,EAAE,sBAAsB,CAAA;IAC5B,qEAAqE;IACrE,MAAM,EAAE,UAAU,CAAA;CACnB;AAED,6FAA6F;AAC7F,MAAM,WAAW,eAAe;IAC9B,EAAE,EAAE,MAAM,CAAA;IACV,KAAK,EAAE,MAAM,CAAA;IACb,IAAI,EAAE,MAAM,GAAG,MAAM,CAAA;IACrB,KAAK,EAAE,MAAM,CAAA;IACb,IAAI,EAAE,sBAAsB,CAAA;IAC5B,OAAO,EAAE,MAAM,EAAE,CAAA;IACjB,wDAAwD;IACxD,QAAQ,EAAE,MAAM,CAAA;IAChB,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,4DAA4D;IAC5D,MAAM,EAAE;QAAE,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,EAAE,MAAM,CAAA;KAAE,CAAA;IAChC,sFAAsF;IACtF,SAAS,EAAE,MAAM,CAAA;IACjB,uBAAuB;IACvB,QAAQ,EAAE,MAAM,CAAA;IAChB,KAAK,EAAE,SAAS,CAAA;IAChB,oFAAoF;IACpF,OAAO,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAA;CAC1D;AAED,+GAA+G;AAC/G,wBAAgB,kBAAkB,CAAC,WAAW,EAAE,2BAA2B,GAAG,SAAS,GAAG,eAAe,EAAE,CA0B1G"}
|