mirror of
https://github.com/Matysh/houseplan-card
synced 2026-09-29 03:09:36 +00:00
refactor: one function owns the junction geometry of a space (#229 r2 M1)
Дефект High-1 был одинаковым в двух местах — и в живом рисовании, и в
«Оптимизировать планы», — потому что каждый вызывающий собирал геометрию
примыканий сам. Ревью r2 справедливо заметило, что и защита получилась
однобокой: юнит и мутант сторожили только оптимизатор, а путь карты — тот, где
дефект и был виден пользователю, — не сторожил никто. Заплатка в виде второго
мутанта-близнеца оставила бы причину на месте: два списка координат, которые
обязаны совпадать, но ничем не связаны.
Поэтому геометрия переехала в `spaceMergeGeometry(space, { excludeDraftId })`:
один источник комнат, колонн и концов черновиков, одни координаты, одно место,
где можно ошибиться. Оба вызывающих теперь строчка вызова.
Покрытие идёт за причиной, а не за симптомом: три юнита в
`test/wall-merge.test.mjs` проверяют масштаб полигонов (включая комнаты в форме
x/y/w/h и комнату без геометрии), исключение активного черновика и сам T-стык к
середине стороны комнаты. Мутанты `partition-merge-rescales-rooms` и
`chain-merge-sees-own-draft` перенацелены на общий модуль и теперь краснеют для
обоих путей сразу: 2 и 1 падение, проверено применением патча.
Сценарий с комнатой в смоке пробовал — не взлетел: рисование в комнату
поднимает `_offerWallFaces`, и цепочка не завершается штатно. Ломать смок под
тест не стал, юниты общего модуля покрывают оба пути честнее.
Issue: #229
User-Visible: no
This commit is contained in:
@@ -4,6 +4,7 @@ import test from 'node:test';
|
||||
import assert from 'node:assert/strict';
|
||||
import {
|
||||
applyOpeningMoves, EPS_JOIN, mergeCollinearPartitions, junctionAt, remapHostT,
|
||||
spaceMergeGeometry,
|
||||
} from '../test-build/wall-merge.js';
|
||||
|
||||
const PITCH = 10; // one grid pitch in test coordinates
|
||||
@@ -210,3 +211,52 @@ test('issue 229 openings hosted elsewhere are left alone', () => {
|
||||
assert.equal(moved, 0);
|
||||
assert.equal(JSON.stringify(openings), before);
|
||||
});
|
||||
|
||||
test('issue 229 space geometry keeps rooms in the coordinates partitions use', () => {
|
||||
// Both callers used to build this themselves and both rescaled the polygon,
|
||||
// so a junction on a room side was never found (CODE-REVIEW-229-r1 High-1,
|
||||
// r2 Medium-1). One function now, checked in the units both paths share.
|
||||
const space = {
|
||||
rooms: [
|
||||
{ id: 'r1', poly: [[0.1, 0.1], [0.5, 0.1], [0.5, 0.5], [0.1, 0.5]] },
|
||||
{ id: 'r2', x: 0.6, y: 0.1, w: 0.2, h: 0.2 },
|
||||
{ id: 'broken' },
|
||||
],
|
||||
wall_columns: [{ id: 'c1', center: [0.7, 0.7] }],
|
||||
};
|
||||
const geometry = spaceMergeGeometry(space);
|
||||
assert.deepEqual(geometry.roomPolygons[0], [[0.1, 0.1], [0.5, 0.1], [0.5, 0.5], [0.1, 0.5]]);
|
||||
assert.deepEqual(geometry.roomPolygons[1][0], [0.6, 0.1], 'x/y/w/h rooms come through too');
|
||||
assert.equal(geometry.roomPolygons.length, 2, 'a room without geometry is skipped');
|
||||
assert.deepEqual(geometry.columns, space.wall_columns);
|
||||
});
|
||||
|
||||
test('issue 229 the chain being finished is not its own junction', () => {
|
||||
const space = {
|
||||
rooms: [],
|
||||
room_drafts: [
|
||||
{ id: 'active', points: [[0.1, 0.1], [0.3, 0.1]] },
|
||||
{ id: 'other', points: [[0.6, 0.6], [0.8, 0.6]] },
|
||||
],
|
||||
};
|
||||
assert.deepEqual(
|
||||
spaceMergeGeometry(space).draftEnds,
|
||||
[[0.1, 0.1], [0.3, 0.1], [0.6, 0.6], [0.8, 0.6]],
|
||||
'without an active chain every draft anchors a node',
|
||||
);
|
||||
assert.deepEqual(
|
||||
spaceMergeGeometry(space, { excludeDraftId: 'active' }).draftEnds,
|
||||
[[0.6, 0.6], [0.8, 0.6]],
|
||||
'the chain about to disappear does not hold a node',
|
||||
);
|
||||
});
|
||||
|
||||
test('issue 229 a junction on a room side survives, through the shared geometry', () => {
|
||||
const partitions = [seg('p1', 100, 500, 300, 500), seg('p2', 300, 500, 500, 500)];
|
||||
const space = { rooms: [{ id: 'r1', x: 100, y: 100, w: 400, h: 400 }] };
|
||||
const result = mergeCollinearPartitions(partitions, {
|
||||
pitch: PITCH, geometry: spaceMergeGeometry(space),
|
||||
});
|
||||
assert.equal(result.merged, 0, 'the middle of the room side holds the node');
|
||||
assert.equal(result.partitions.length, 2);
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user