mirror of
https://github.com/Matysh/houseplan-card
synced 2026-09-29 03:09:36 +00:00
feat: a straight wall is one record, not a row of seams (#229)
Рисование прямой стены в несколько кликов оставляло по записи на каждый отрезок. Швы невидимы, пока их не тронешь: выделение хватает кусок, перетаскивание ломает стену пополам, толщина задаётся пофрагментно. У стен комнат этого давно нет — `normalizeWallIntervals` схлопывает каждый сплошной участок одной толщины. Независимые перегородки жили по другому правилу. Новый чистый модуль `src/wall-merge.ts` даёт им то же правило: - `mergeCollinearPartitions` сращивает соседей одинаковой толщины и направления до неподвижной точки, но только там, где узел никому не нужен. Узел остаётся, если в него приходит третья перегородка, стена комнаты (стороной, а не только вершиной), колонна или конец сохранённого черновика. - Направление выжившей записи канонизируется лексикографически: иначе одна и та же физическая стена выходила то a→b, то b→a в зависимости от порядка входа, и каждый host.t вдоль неё переворачивался вместе с ней. - `applyOpeningMoves` переносит проёмы на выжившую запись: и авторитетный `host`, и legacy-проекцию `x/y/angle`, которую рисует старый читатель конфига (docs/CONFIG-COMPATIBILITY.md, #132). Проекция здесь не кэш — канонизация направления разворачивает угол на 180°. Рисование сращивает только свою цепочку и то, чего она коснулась (§8.6 ТЗ): молча править чужие швы в стороне оно не вправе — для этого есть «Оптимизировать планы» с предпросмотром, отчётом и отменой. Оптимизация проходит по всему пространству без seed-ограничения и отдельной строкой сообщает, сколько записей исчезло. Issue: #229 User-Visible: yes
This commit is contained in:
@@ -717,6 +717,85 @@ export const MUTANTS = [
|
||||
replace: ' .dev:not(.unavail):hover {',
|
||||
}],
|
||||
},
|
||||
{
|
||||
id: 'partition-merge-disabled',
|
||||
guard: 'node demo/smoke_wall_chain_merge.mjs',
|
||||
because: 'без вызова слияния прямая, нарисованная в несколько кликов, снова хранится '
|
||||
+ 'набором отрезков со швами на каждом стыке (#229)',
|
||||
patches: [{
|
||||
file: 'src/houseplan-card.ts',
|
||||
find: ' this._mergeSpacePartitions(sp, drawnIds);',
|
||||
replace: ' void drawnIds;',
|
||||
}],
|
||||
},
|
||||
{
|
||||
id: 'partition-merge-ignores-thickness',
|
||||
guard: 'node --test --test-name-pattern="issue 229" test/wall-merge.test.mjs',
|
||||
because: 'сращивание отрезков разной толщины стирает намеренный переход толщины стены',
|
||||
patches: [{
|
||||
file: 'src/wall-merge.ts',
|
||||
find: ' if (p.cm !== q.cm) return null;',
|
||||
replace: ' if (false) return null;',
|
||||
}],
|
||||
},
|
||||
{
|
||||
id: 'partition-merge-ignores-junction',
|
||||
guard: 'node --test --test-name-pattern="issue 229" test/wall-merge.test.mjs',
|
||||
because: 'слияние сквозь примыкание убирает узел, который держит третья стена, '
|
||||
+ 'комната, колонна или черновик — §8.2 ТЗ',
|
||||
patches: [{
|
||||
file: 'src/wall-merge.ts',
|
||||
find: ' if (junctionAt(at, list, new Set([list[i].id, list[j].id]), options.geometry, join)) continue;',
|
||||
replace: ' if (false) continue;',
|
||||
}],
|
||||
},
|
||||
{
|
||||
id: 'junction-checks-room-vertices-only',
|
||||
guard: 'node --test --test-name-pattern="issue 229" test/wall-merge.test.mjs',
|
||||
because: 'поиск примыкания комнаты только по вершинам пропускает T-стык к середине '
|
||||
+ 'комнатной стены — штатный случай продукта (docs/specs/141-wall-junctions.md)',
|
||||
patches: [{
|
||||
file: 'src/wall-merge.ts',
|
||||
find: ' if (finite(a) && finite(b) && distToSegment(point, a, b) <= join) return true;',
|
||||
replace: ' if (finite(a) && dist(point, a) <= join) return true; void b;',
|
||||
}],
|
||||
},
|
||||
{
|
||||
id: 'partition-merge-keeps-relative-t',
|
||||
guard: 'node --test --test-name-pattern="issue 229" test/wall-merge.test.mjs',
|
||||
because: 'сохранение прежней доли вместо пересчёта двигает дверь вдоль стены: '
|
||||
+ 'позиция проёма относительна длине хозяина, а она при слиянии меняется',
|
||||
patches: [{
|
||||
file: 'src/wall-merge.ts',
|
||||
find: ' const mapped = move.base + t * move.span;',
|
||||
replace: ' const mapped = t;',
|
||||
}],
|
||||
},
|
||||
{
|
||||
id: 'partition-merge-skips-materialization',
|
||||
guard: 'node --test --test-name-pattern="issue 229" test/wall-merge.test.mjs',
|
||||
because: 'устаревшие x/y/angle — это то, что рисует старый читатель конфига; '
|
||||
+ 'слияние канонизирует направление стены, поэтому проекция обязана '
|
||||
+ 'переписаться (docs/CONFIG-COMPATIBILITY.md, #132)',
|
||||
patches: [{
|
||||
file: 'src/wall-merge.ts',
|
||||
find: ` if (resolved) Object.assign(
|
||||
opening, materializePartitionOpening(opening, resolved, ctx.coordScale),
|
||||
);`,
|
||||
replace: ' void resolved;',
|
||||
}],
|
||||
},
|
||||
{
|
||||
id: 'chain-merge-sweeps-whole-space',
|
||||
guard: 'node --test --test-name-pattern="issue 229" test/wall-merge.test.mjs',
|
||||
because: 'слияние всего пространства при рисовании молча правит старые швы в стороне, '
|
||||
+ 'минуя отчёт и отмену, которые обещаны им в «Оптимизировать планы» (§8.6 ТЗ)',
|
||||
patches: [{
|
||||
file: 'src/wall-merge.ts',
|
||||
find: ' if (seeds && !seeds.has(list[i].id) && !seeds.has(list[j].id)) continue;',
|
||||
replace: ' if (false) continue;',
|
||||
}],
|
||||
},
|
||||
{
|
||||
id: 'tab-reorder-not-persisted',
|
||||
guard: 'node demo/smoke_space_tab_reorder.mjs',
|
||||
|
||||
Reference in New Issue
Block a user