mirror of
https://github.com/Matysh/houseplan-card
synced 2026-10-04 05:41:34 +00:00
@@ -36,7 +36,7 @@ test('issue 276 reconciles the anonymized 5 cm offset fixture without moving its
|
||||
assert.equal(space.openings.length, 1);
|
||||
assert.deepEqual(space.openings[0], {
|
||||
id: 'hosted-door', type: 'door',
|
||||
x: 0.504166667, y: 0.5, angle: -90, length: 0.2,
|
||||
x: 121 / 240, y: 0.5, angle: -90, length: 0.2,
|
||||
contact: 'binary_sensor.test_door', lock: 'lock.test_door',
|
||||
invert: true, flip_h: true, future_field: { keep: true },
|
||||
});
|
||||
@@ -100,7 +100,7 @@ test('issue 276 rehosts three non-overlapping door/window/gate openings atomical
|
||||
['hosted-door', 'hosted-window', 'hosted-gate']);
|
||||
assert.deepEqual(openings.map((opening) => opening.type), ['door', 'window', 'gate']);
|
||||
assert.ok(openings.every((opening) => opening.host === undefined));
|
||||
assert.ok(openings.every((opening) => opening.x === 0.504166667));
|
||||
assert.ok(openings.every((opening) => opening.x === 121 / 240));
|
||||
assert.ok(openings[0].y < openings[1].y && openings[1].y < openings[2].y);
|
||||
assert.equal(openings[0].contact, 'binary_sensor.door');
|
||||
assert.equal(openings[1].cover, 'cover.window');
|
||||
|
||||
@@ -4,10 +4,16 @@ import test from 'node:test';
|
||||
|
||||
import {
|
||||
COORDINATE_DECIMALS,
|
||||
LATTICE_GRID_N,
|
||||
LATTICE_NOISE_STEPS,
|
||||
canonicalizeConfigGeometry,
|
||||
canonicalizeConfigGeometryInPlace,
|
||||
canonicalizeLatticeCoordinate,
|
||||
canonicalizeLayoutGeometry,
|
||||
canonicalizeNumber,
|
||||
canonicalizePosition,
|
||||
formatLatticeShiftCm,
|
||||
latticeCanonicalizationReport,
|
||||
} from '../test-build/coordinate-canonicalization.js';
|
||||
|
||||
const fixture = JSON.parse(readFileSync(
|
||||
@@ -15,7 +21,7 @@ const fixture = JSON.parse(readFileSync(
|
||||
'utf8',
|
||||
));
|
||||
|
||||
test('frontend and backend share the nine-decimal fixture contract (#224)', () => {
|
||||
test('frontend and backend share the scalar+lattice fixture contract (#291)', () => {
|
||||
assert.equal(COORDINATE_DECIMALS, fixture.decimals);
|
||||
const configBefore = structuredClone(fixture.configInput);
|
||||
const layoutBefore = structuredClone(fixture.layoutInput);
|
||||
@@ -41,13 +47,64 @@ test('scalar canonicalization is symmetric and never snaps off-grid geometry (#2
|
||||
assert.equal(canonicalizeNumber(Number.POSITIVE_INFINITY), Number.POSITIVE_INFINITY);
|
||||
});
|
||||
|
||||
test('all 4801 lattice nodes and their nine-decimal forms share exact bits (#291)', () => {
|
||||
assert.equal(LATTICE_GRID_N, 240);
|
||||
assert.equal(LATTICE_NOISE_STEPS, 1e-4);
|
||||
for (let k = -2400; k <= 2400; k++) {
|
||||
const node = k / LATTICE_GRID_N;
|
||||
const nineDecimal = Number(node.toFixed(COORDINATE_DECIMALS));
|
||||
assert.equal(canonicalizeLatticeCoordinate(node), node, `node ${k}`);
|
||||
assert.equal(canonicalizeLatticeCoordinate(nineDecimal), node, `stored node ${k}`);
|
||||
assert.equal(canonicalizeLatticeCoordinate(
|
||||
canonicalizeLatticeCoordinate(nineDecimal),
|
||||
), node, `idempotent node ${k}`);
|
||||
}
|
||||
assert.equal(Object.is(canonicalizeLatticeCoordinate(-0), -0), false);
|
||||
assert.equal(canonicalizeLatticeCoordinate(0.06), 0.06);
|
||||
assert.equal(canonicalizeLatticeCoordinate(0.2875), 0.2875);
|
||||
assert.equal(canonicalizeLatticeCoordinate((1 + 0.999e-4) / 240), 1 / 240);
|
||||
assert.equal(canonicalizeLatticeCoordinate((1 + 1.001e-4) / 240), 0.004167084);
|
||||
});
|
||||
|
||||
test('lattice report separates noise, far values and physical per-space maxima (#291)', () => {
|
||||
const node = 83 / 240;
|
||||
const noise = Number(node.toFixed(9));
|
||||
const report = latticeCanonicalizationReport({ spaces: [
|
||||
{ id: 'quiet', title: 'Quiet', cell_cm: 1, rooms: [{ poly: [[0, 0], [0.06, 0]] }] },
|
||||
{ id: 'touched', title: 'Touched', cell_cm: 10, rooms: [{ poly: [[noise, node], [0.06, 0]] }] },
|
||||
] }, { marker: { s: 'touched', x: noise, y: 0 }, orphan: { x: noise, y: 0 } });
|
||||
assert.equal(report.canonicalized, 3);
|
||||
assert.equal(report.far, 2);
|
||||
assert.equal(report.spaces.length, 1, 'unchanged spaces stay out of the breakdown');
|
||||
assert.deepEqual(report.spaces[0], {
|
||||
spaceId: 'touched', space: 'Touched', canonicalized: 2, far: 1,
|
||||
maxShift: Math.abs(node - noise),
|
||||
maxShiftCm: Math.abs(node - noise) * 240 * 10,
|
||||
});
|
||||
assert.equal(report.maxShift, Math.abs(node - noise));
|
||||
assert.equal(report.maxShiftCm, Math.abs(node - noise) * 240 * 10);
|
||||
});
|
||||
|
||||
test('lattice movement format keeps three significant digits without fake 0.1 cm (#291)', () => {
|
||||
assert.equal(formatLatticeShiftCm(0), '0');
|
||||
assert.equal(formatLatticeShiftCm(0.000033), '3.30e-5');
|
||||
assert.equal(formatLatticeShiftCm(0.0012345), '0.00123');
|
||||
assert.equal(formatLatticeShiftCm(1.2), '1.2');
|
||||
});
|
||||
|
||||
test('Optimize can apply the same barrier in-place without a second clone (#291)', () => {
|
||||
const input = structuredClone(fixture.configInput);
|
||||
assert.equal(canonicalizeConfigGeometryInPlace(input), input);
|
||||
assert.deepEqual(input, fixture.configExpected);
|
||||
});
|
||||
|
||||
test('one position changes only x/y and preserves future metadata (#224)', () => {
|
||||
const input = {
|
||||
s: 'floor', x: 0.1000000006, y: -0.0000000004,
|
||||
k: 1.0000000004, nested: { numeric: 0.1234567896 },
|
||||
};
|
||||
assert.deepEqual(canonicalizePosition(input), {
|
||||
s: 'floor', x: 0.100000001, y: 0,
|
||||
s: 'floor', x: 0.1, y: 0,
|
||||
k: 1.0000000004, nested: { numeric: 0.1234567896 },
|
||||
});
|
||||
});
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
import assert from 'node:assert/strict';
|
||||
import test from 'node:test';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
|
||||
import { checkCoordinateWriteBarriers } from '../scripts/coordinate-write-barrier-guard.mjs';
|
||||
|
||||
const repoRoot = fileURLToPath(new URL('..', import.meta.url));
|
||||
|
||||
test('all frontend and backend coordinate writers converge on one boundary (#291)', () => {
|
||||
assert.deepEqual(checkCoordinateWriteBarriers(repoRoot), []);
|
||||
});
|
||||
+8
-8
@@ -12,9 +12,9 @@
|
||||
"name": "Left",
|
||||
"area": null,
|
||||
"poly": [
|
||||
[0, 0], [0.5, 0], [0.5, 0.004166667],
|
||||
[0.504166667, 0.004166667], [0.504166667, 0.995833333],
|
||||
[0.5, 0.995833333], [0.5, 1], [0, 1]
|
||||
[0, 0], [0.5, 0], [0.5, 0.004166666666666667],
|
||||
[0.5041666666666667, 0.004166666666666667], [0.5041666666666667, 0.9958333333333333],
|
||||
[0.5, 0.9958333333333333], [0.5, 1], [0, 1]
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -22,8 +22,8 @@
|
||||
"name": "Right",
|
||||
"area": null,
|
||||
"poly": [
|
||||
[0.504166667, 0.004166667], [1, 0.004166667],
|
||||
[1, 0.995833333], [0.504166667, 0.995833333]
|
||||
[0.5041666666666667, 0.004166666666666667], [1, 0.004166666666666667],
|
||||
[1, 0.9958333333333333], [0.5041666666666667, 0.9958333333333333]
|
||||
]
|
||||
}
|
||||
],
|
||||
@@ -31,15 +31,15 @@
|
||||
{
|
||||
"key": "0.504167,0.500000@1.5706",
|
||||
"cm": 20,
|
||||
"a": [0.504166667, 0.004166667],
|
||||
"b": [0.504166667, 0.995833333]
|
||||
"a": [0.5041666666666667, 0.004166666666666667],
|
||||
"b": [0.5041666666666667, 0.9958333333333333]
|
||||
}
|
||||
],
|
||||
"openings": [
|
||||
{
|
||||
"id": "hosted-door",
|
||||
"type": "door",
|
||||
"x": 0.504166667,
|
||||
"x": 0.5041666666666667,
|
||||
"y": 0.5,
|
||||
"angle": -90,
|
||||
"length": 0.2,
|
||||
|
||||
+19
-19
@@ -241,9 +241,9 @@
|
||||
"name": "Rect",
|
||||
"area": null,
|
||||
"x": 0.4,
|
||||
"y": 0.400000001,
|
||||
"y": 0.4,
|
||||
"w": 0.2,
|
||||
"h": 0.200000001
|
||||
"h": 0.2
|
||||
}
|
||||
],
|
||||
"walls": [
|
||||
@@ -251,7 +251,7 @@
|
||||
"key": "wall",
|
||||
"cm": 15.0000000004,
|
||||
"a": [0, 0.3],
|
||||
"b": [0.300000001, 0.300000001]
|
||||
"b": [0.3, 0.3]
|
||||
}
|
||||
],
|
||||
"openings": [
|
||||
@@ -274,9 +274,9 @@
|
||||
"id": "line",
|
||||
"kind": "line",
|
||||
"x1": 0.1,
|
||||
"y1": 0.100000001,
|
||||
"y1": 0.1,
|
||||
"x2": 0.2,
|
||||
"y2": 0.200000001,
|
||||
"y2": 0.2,
|
||||
"width_cm": 2.0000000004,
|
||||
"opacity": 0.7000000004
|
||||
},
|
||||
@@ -284,9 +284,9 @@
|
||||
"id": "rect-decor",
|
||||
"kind": "rect",
|
||||
"x": 0.1,
|
||||
"y": 0.200000001,
|
||||
"y": 0.2,
|
||||
"w": 0.3,
|
||||
"h": 0.400000001,
|
||||
"h": 0.4,
|
||||
"angle": 12.12345679,
|
||||
"fill_opacity": 0.6000000004
|
||||
},
|
||||
@@ -294,8 +294,8 @@
|
||||
"id": "ellipse",
|
||||
"kind": "ellipse",
|
||||
"x": -0.1,
|
||||
"y": -0.200000001,
|
||||
"w": 0.300000001,
|
||||
"y": -0.2,
|
||||
"w": 0.3,
|
||||
"h": 0.4,
|
||||
"angle": -12.12345679
|
||||
},
|
||||
@@ -303,7 +303,7 @@
|
||||
"id": "text",
|
||||
"kind": "text",
|
||||
"x": 0.7,
|
||||
"y": 0.800000001,
|
||||
"y": 0.8,
|
||||
"text": "Text",
|
||||
"scale": 1.234567891,
|
||||
"angle": 2.12345679,
|
||||
@@ -314,9 +314,9 @@
|
||||
"kind": "furniture",
|
||||
"symbol": "chair",
|
||||
"x": 0.6,
|
||||
"y": 0.600000001,
|
||||
"y": 0.6,
|
||||
"w": 0.1,
|
||||
"h": 0.100000001,
|
||||
"h": 0.1,
|
||||
"angle": 90.12345679
|
||||
}
|
||||
],
|
||||
@@ -324,9 +324,9 @@
|
||||
{
|
||||
"id": "draft",
|
||||
"points": [
|
||||
[0.1, 0.900000001],
|
||||
[0.200000001, 0.9],
|
||||
[0.3, 0.900000001]
|
||||
[0.1, 0.9],
|
||||
[0.2, 0.9],
|
||||
[0.3, 0.9]
|
||||
],
|
||||
"segments": [
|
||||
{"cm": 10.0000000004},
|
||||
@@ -346,15 +346,15 @@
|
||||
{
|
||||
"id": "column",
|
||||
"shape": "square",
|
||||
"center": [0.75, 0.750000001],
|
||||
"center": [0.75, 0.75],
|
||||
"cm": 30.0000000004,
|
||||
"angle": 45.12345679
|
||||
}
|
||||
],
|
||||
"open_spans": [
|
||||
{
|
||||
"a": [0.3, 0.300000001],
|
||||
"b": [0.600000001, 0.3]
|
||||
"a": [0.3, 0.3],
|
||||
"b": [0.6, 0.3]
|
||||
}
|
||||
],
|
||||
"future": {
|
||||
@@ -428,7 +428,7 @@
|
||||
"rl:poly": {
|
||||
"s": "floor",
|
||||
"x": 0,
|
||||
"y": 0.750000001,
|
||||
"y": 0.75,
|
||||
"k": 1.5000000004
|
||||
}
|
||||
}
|
||||
|
||||
+6
-6
@@ -70,10 +70,10 @@
|
||||
"id": "fine-room",
|
||||
"name": "Fine room",
|
||||
"poly": [
|
||||
[0.004166667, 0],
|
||||
[0.008333333, 0],
|
||||
[0.008333333, 0.008333333],
|
||||
[0.004166667, 0.008333333]
|
||||
[0.004166666666666667, 0],
|
||||
[0.008333333333333333, 0],
|
||||
[0.008333333333333333, 0.008333333333333333],
|
||||
[0.004166666666666667, 0.008333333333333333]
|
||||
]
|
||||
}
|
||||
]
|
||||
@@ -103,8 +103,8 @@
|
||||
"layout": {
|
||||
"sensor.fine": {
|
||||
"s": "fine",
|
||||
"x": 0.004166667,
|
||||
"y": 0.008333333
|
||||
"x": 0.004166666666666667,
|
||||
"y": 0.008333333333333333
|
||||
},
|
||||
"sensor.regular": {
|
||||
"s": "regular",
|
||||
|
||||
+23
-1
@@ -62,7 +62,29 @@ test('Optimize distinguishes updated spaces from cleaned coordinate noise', () =
|
||||
assert.match(cardSource, /i: String\(r\.partitionsMerged\)/);
|
||||
assert.match(cardSource, /gs\.optimize_coincident_partitions/);
|
||||
assert.match(cardSource, /gs\.optimize_openings_rehosted/);
|
||||
assert.match(cardSource, /d\.report\.coordsCanonicalized \+ d\.report\.wallsMerged/);
|
||||
assert.match(cardSource,
|
||||
/d\.report\.coordsCanonicalized \+ d\.report\.latticeCoordinatesCanonicalized/);
|
||||
});
|
||||
|
||||
test('issue 291 Optimize reports lattice cleanup separately in both languages', () => {
|
||||
assert.equal(
|
||||
en['gs.optimize_lattice_summary'],
|
||||
'Noisy coordinate values canonicalized: {n}; maximum movement: {cm} cm.',
|
||||
);
|
||||
assert.equal(
|
||||
ru['gs.optimize_lattice_summary'],
|
||||
'Канонизировано шумовых значений координат: {n}; максимальный сдвиг: {cm} см.',
|
||||
);
|
||||
assert.equal(
|
||||
en['gs.optimize_lattice_space'],
|
||||
'{space}: coordinate values canonicalized: {n}; off-grid values left unchanged: {far}.',
|
||||
);
|
||||
assert.equal(
|
||||
ru['gs.optimize_lattice_space'],
|
||||
'{space}: канонизировано значений координат: {n}; оставлено значений вне сетки: {far}.',
|
||||
);
|
||||
assert.match(cardSource, /formatLatticeShiftCm\(r\.latticeMaxShiftCm\)/);
|
||||
assert.match(cardSource, /r\.latticeSpaces\.map/);
|
||||
});
|
||||
|
||||
test('issue 252 Optimize keeps internal ids out of the main orphan report', () => {
|
||||
|
||||
@@ -10,6 +10,9 @@ import {
|
||||
} from '../scripts/model-invariants.mjs';
|
||||
import { wallKey as productWallKey } from '../test-build/wall-thickness.js';
|
||||
import { GRID_STEP_N } from '../test-build/space-geometry.js';
|
||||
import {
|
||||
canonicalizeConfigGeometry, latticeCanonicalizationReport,
|
||||
} from '../test-build/coordinate-canonicalization.js';
|
||||
|
||||
const repoRoot = fileURLToPath(new URL('..', import.meta.url));
|
||||
|
||||
@@ -355,6 +358,28 @@ test('профиль видит все виды объектов, а не тол
|
||||
assert.equal(profile.total, 18);
|
||||
});
|
||||
|
||||
test('профиль решётки покрывает полный persisted allow-list (#291)', () => {
|
||||
const off = 0.0605;
|
||||
const profile = latticeProfile({
|
||||
config: { spaces: [{
|
||||
id: 'sp1',
|
||||
rooms: [{ id: 'legacy', x: off, y: off, w: off, h: off }],
|
||||
openings: [{ id: 'door', x: off, y: off }],
|
||||
room_drafts: [{ id: 'draft', points: [[off, off]] }],
|
||||
decor: [
|
||||
{ id: 'line', kind: 'line', x1: off, y1: off, x2: off, y2: off },
|
||||
{ id: 'rect', kind: 'rect', x: off, y: off, w: off, h: off },
|
||||
{ id: 'text', kind: 'text', x: off, y: off },
|
||||
],
|
||||
}] },
|
||||
layout: {},
|
||||
});
|
||||
assert.deepEqual(Object.keys(profile.byKind).sort(),
|
||||
['decor', 'opening', 'room', 'room_draft']);
|
||||
assert.equal(profile.total, 18);
|
||||
assert.equal(profile.offGrid, 18);
|
||||
});
|
||||
|
||||
test('модели проекта не несут шума решётки (#282)', async () => {
|
||||
// Свойство, которое стоит знать про себя: тестовые данные проекта чисты —
|
||||
// весь их офф-грид авторский. Значит воспроизвести на них #258/#279 нельзя
|
||||
@@ -403,6 +428,24 @@ test('реальные планы сохраняют координатный ш
|
||||
}
|
||||
});
|
||||
|
||||
test('барьер очищает клоны реальных планов, не переписывая source fixtures (#291)', () => {
|
||||
for (const plan of REAL_PLANS) {
|
||||
const path = resolve(repoRoot, 'test/fixtures', plan.file);
|
||||
const rawBefore = readFileSync(path, 'utf8');
|
||||
const { space } = JSON.parse(rawBefore);
|
||||
const source = { spaces: [space], markers: [], settings: {} };
|
||||
const measured = latticeCanonicalizationReport(source, {});
|
||||
assert.ok(measured.canonicalized >= plan.minNoise, `${plan.file}: cleanup must be measurable`);
|
||||
const candidate = canonicalizeConfigGeometry(source);
|
||||
const profile = latticeProfile({ config: candidate, layout: {} });
|
||||
assert.equal(profile.noise, 0, `${plan.file}: boundary must remove all near-node tails`);
|
||||
assert.equal(profile.offGrid, measured.far, `${plan.file}: authored off-grid population survives`);
|
||||
assert.equal(checkWallKeys(candidate, { notes: [] }).length, 0);
|
||||
assert.equal(checkMixedRoleRecords(candidate).length, 0);
|
||||
assert.equal(readFileSync(path, 'utf8'), rawBefore, 'the raw regression fixture is immutable');
|
||||
}
|
||||
});
|
||||
|
||||
test('реальные планы: сплошные рёбра без записи толщины закреплены числом (#286)', async () => {
|
||||
// Ребро, объявленное сплошным, но с нулевой толщиной, рисуется без кладки.
|
||||
// На первом этаже таких два, длиной по 2 шага, и соседние тела их накрывают —
|
||||
|
||||
@@ -6,7 +6,7 @@ import {
|
||||
collapseIsolatedWallThicknessIslands, optimizePlans, PLAN_MODEL_VERSION,
|
||||
} from '../test-build/plan-optimizer.js';
|
||||
import {
|
||||
canonicalizeConfigGeometry, canonicalizeLayoutGeometry, canonicalizeNumber,
|
||||
canonicalizeConfigGeometry, canonicalizeLatticeCoordinate, canonicalizeLayoutGeometry,
|
||||
} from '../test-build/coordinate-canonicalization.js';
|
||||
import { pointInPhysicalGeometry, unionBodies } from '../test-build/physical-geometry.js';
|
||||
import { GRID_PITCH, GRID_STEP_N as S, NORM_W } from '../test-build/space-geometry.js';
|
||||
@@ -48,7 +48,10 @@ const assertNoPersistedChanges = (result) => {
|
||||
'positionsRemapped', 'markersDetached', 'orphanRoomLabelsRemoved',
|
||||
'orphanDevicePositionsRemoved', 'orphanGroupPositionsRemoved',
|
||||
'liveMissingPositionsRemoved',
|
||||
'latticeCoordinatesCanonicalized', 'latticeCoordinatesFar',
|
||||
'latticeMaxShift', 'latticeMaxShiftCm',
|
||||
]) assert.equal(result.report[field], 0, `${field} must describe the persisted delta`);
|
||||
assert.deepEqual(result.report.latticeSpaces, []);
|
||||
assert.equal(result.report.maxShift, 0);
|
||||
assert.equal(result.report.maxShiftCm, 0);
|
||||
assert.equal(result.report.maxSpace, '');
|
||||
@@ -237,8 +240,9 @@ test('issue 273 Optimize collapses the beta.5 island beside one T-node', () => {
|
||||
'T coordinate and perpendicular incident room stay byte-equivalent');
|
||||
assert.equal(first.config.spaces[0].walls.length, 1);
|
||||
assert.equal(first.config.spaces[0].walls[0].cm, 22);
|
||||
assert.deepEqual(first.config.spaces[0].walls[0].a, [0.8, 0.345833333]);
|
||||
assert.deepEqual(first.config.spaces[0].walls[0].b, [0.95, 0.345833333]);
|
||||
const exactNode = 83 / 240;
|
||||
assert.deepEqual(first.config.spaces[0].walls[0].a, [0.8, exactNode]);
|
||||
assert.deepEqual(first.config.spaces[0].walls[0].b, [0.95, exactNode]);
|
||||
|
||||
const afterIntervals = wallIntervals(
|
||||
first.config.spaces[0].rooms, first.config.spaces[0].walls, [], S, 5, S,
|
||||
@@ -250,7 +254,7 @@ test('issue 273 Optimize collapses the beta.5 island beside one T-node', () => {
|
||||
assert.ok(geometry, 'optimized profile must render a masonry body');
|
||||
for (const x of [fixture.split - S, (fixture.split + fixture.microEnd) / 2,
|
||||
fixture.microEnd + S]) {
|
||||
assert.equal(pointInPhysicalGeometry([x, 0.345833333 - 0.008], geometry.geom), true,
|
||||
assert.equal(pointInPhysicalGeometry([x, exactNode - 0.008], geometry.geom), true,
|
||||
`22 cm outer face must stay continuous at x=${x}`);
|
||||
}
|
||||
|
||||
@@ -276,12 +280,14 @@ test('Optimize canonicalizes the six-room ULP source without claiming a visible
|
||||
assert.equal(first.report.moved, 0);
|
||||
assert.equal(first.report.maxShift, 0);
|
||||
assert.equal(first.report.maxShiftCm, 0);
|
||||
assert.ok(first.report.coordsCanonicalized > 0);
|
||||
assert.ok(first.report.latticeCoordinatesCanonicalized > 0);
|
||||
assert.equal(first.report.coordsCanonicalized, 0,
|
||||
'storage-only tails are not presented as visible grid alignment');
|
||||
assert.deepEqual(first.config.future, { kept: true });
|
||||
for (const item of first.config.spaces[0].rooms) {
|
||||
for (const [x, y] of item.poly) {
|
||||
assert.equal(x, canonicalizeNumber(Math.round(x / S) * S));
|
||||
assert.equal(y, canonicalizeNumber(Math.round(y / S) * S));
|
||||
assert.equal(x, canonicalizeLatticeCoordinate(Math.round(x / S) * S));
|
||||
assert.equal(y, canonicalizeLatticeCoordinate(Math.round(y / S) * S));
|
||||
}
|
||||
}
|
||||
assert.ok(unionBodies(first.config.spaces[0].rooms.map((item) => item.poly)),
|
||||
@@ -290,11 +296,12 @@ test('Optimize canonicalizes the six-room ULP source without claiming a visible
|
||||
const second = optimizePlans(first.config, first.layout);
|
||||
assert.equal(second.changed, false);
|
||||
assert.equal(second.report.coordsCanonicalized, 0);
|
||||
assert.equal(second.report.latticeCoordinatesCanonicalized, 0);
|
||||
assert.deepEqual(second.config, first.config);
|
||||
assert.deepEqual(second.layout, first.layout);
|
||||
});
|
||||
|
||||
test('issue 248 Optimize stays a no-op across the nine-decimal storage round-trip', () => {
|
||||
test('issue 248 Optimize stays a no-op across the lattice storage round-trip', () => {
|
||||
const inputBefore = structuredClone(storageRoundtripFixture.input);
|
||||
const first = optimizePlans(
|
||||
storageRoundtripFixture.input.config,
|
||||
@@ -303,7 +310,7 @@ test('issue 248 Optimize stays a no-op across the nine-decimal storage round-tri
|
||||
|
||||
assert.deepEqual(storageRoundtripFixture.input, inputBefore, 'preview must keep fixture input');
|
||||
assert.equal(first.changed, true);
|
||||
assert.ok(first.report.coordsCanonicalized > 0);
|
||||
assert.ok(first.report.latticeCoordinatesCanonicalized > 0);
|
||||
assert.deepEqual(first.config, storageRoundtripFixture.expected.config);
|
||||
assert.deepEqual(first.layout, storageRoundtripFixture.expected.layout);
|
||||
assert.deepEqual(canonicalizeConfigGeometry(first.config), first.config);
|
||||
@@ -339,8 +346,9 @@ test('issue 258 Optimize canonicalizes an affected wall key across storage round
|
||||
const repaired = first.config.spaces[0].walls.find((wall) => wall.cm === 29);
|
||||
assert.ok(repaired);
|
||||
assert.equal(repaired.cm, 29);
|
||||
assert.deepEqual(repaired.a, wallKeyRoundtripFixture.space.walls[0].a);
|
||||
assert.deepEqual(repaired.b, wallKeyRoundtripFixture.space.walls[0].b);
|
||||
const canonicalSource = canonicalizeConfigGeometry({ spaces: [wallKeyRoundtripFixture.space] });
|
||||
assert.deepEqual(repaired.a, canonicalSource.spaces[0].walls[0].a);
|
||||
assert.deepEqual(repaired.b, canonicalSource.spaces[0].walls[0].b);
|
||||
assert.equal(repaired.key, wallKeyRoundtripFixture.canonical_key);
|
||||
assert.equal(repaired.key, wallKey(repaired.a, repaired.b, S));
|
||||
assert.deepEqual(canonicalizeConfigGeometry(first.config), first.config);
|
||||
|
||||
Reference in New Issue
Block a user