mirror of
https://github.com/Matysh/houseplan-card
synced 2026-09-30 19:58:50 +00:00
docs: record the owner's chamfer decision and the strip-safe cut contract (#302)
Issue: #302 User-Visible: no
This commit is contained in:
@@ -61,6 +61,12 @@
|
||||
2. **Отдельный полноценный сет тестов со скриншотами стыков крупным планом**:
|
||||
разное число лучей, толщины, углы, виртуальные стены и т.д.
|
||||
3. Детектор дыр как объективный инвариант — в дополнение к скриншотам.
|
||||
4. **Фаска #249 на внешних углах узлов сохраняется** (решение в ходе
|
||||
реализации, 2026-08-25): узлы ≥3 лучей остаются чуть срезанными, как
|
||||
утверждено в #249, а не превращаются в острые mitre-углы. Следствие для
|
||||
контракта: чисто аддитивной модель быть не может — фаска по природе
|
||||
вычитающая; гарантию «нет дыр» несёт strip-safe построение среза (§8.2)
|
||||
плюс детектор, а не отсутствие вычитаний.
|
||||
|
||||
## 5. Цели
|
||||
|
||||
@@ -96,21 +102,27 @@
|
||||
`EPS_NODE = openEps × 4` (текущий допуск `buildMultiWallNodeMap` — сохраняется).
|
||||
Луч приходит в узел со своей полу-толщиной; лучи упорядочиваются по азимуту.
|
||||
|
||||
### 8.2. Аддитивное построение — единственное правило узла
|
||||
### 8.2. Правило узла: веер + strip-safe фаска из одного углового обхода
|
||||
|
||||
Материал узла = union из:
|
||||
Для каждой пары соседних по азимуту лучей (сектор ≤ 180°; рефлексные секторы —
|
||||
внешняя сторона выпуклого угла — пропускаются целиком):
|
||||
|
||||
1. тел лучей (прямоугольные полосы до узла, как сейчас);
|
||||
2. **углового веера между каждой парой соседних по азимуту лучей**: пересечение
|
||||
офсетных прямых двух лучей на обращённой друг к другу стороне даёт
|
||||
mitre-точку; веер — полигон «узел → конец полосы A → mitre → конец полосы B».
|
||||
Если mitre-точка дальше `MITRE_LIMIT × max(толщин)` от узла или прямые
|
||||
параллельны — вместо неё хорда между концами полос (bevel). Правило одно и
|
||||
то же для внешней и внутренней стороны угла и для любого числа лучей.
|
||||
1. **Веер (аддитивно):** полигон «узел → край полосы A → mitre → край полосы B»,
|
||||
где mitre — пересечение обращённых в сектор офсетных прямых. Если mitre
|
||||
дальше **лимита узла** (`node.limit = MULTI_WALL_JOIN_LIMIT × halfDepth`,
|
||||
утверждённая граница #249) — вместо mitre хорда bevel на радиусе лимита.
|
||||
2. **Фаска (вычитающе, strip-safe):** клин за хордой (треугольник
|
||||
«конец A → mitre → конец B») минус **квады всех лучей этого узла** — ещё на
|
||||
этапе построения, до какого-либо `difference` по телу. Срез физически не
|
||||
может задеть материал полос: у острых стыков, где клин перекрывается с
|
||||
полосами, срезается только его свободная часть, и стык остаётся сплошным —
|
||||
это и есть исправление артефактов из issue. У ортогональных T/X клин лежит
|
||||
вне полос, и фаска выглядит ровно как в #249.
|
||||
|
||||
**В узловой механике нет ни одной операции `difference`.** Дыра между телами
|
||||
лучей невозможна по построению: каждый сектор между соседними лучами накрыт
|
||||
веером. «Лишний» материал ограничен тем же `MITRE_LIMIT`, что и сегодня.
|
||||
Инвариант вместо «нет difference»: **тело ⊇ полосы лучей ∪ веера** — материал
|
||||
контракта не может быть удалён ничем, включая фаску (она strip-safe по
|
||||
построению и не пересекается с веером — их разделяет общая хорда). Проверяется
|
||||
детектором §8.4.
|
||||
|
||||
### 8.3. Спец-случаи
|
||||
|
||||
@@ -124,10 +136,13 @@
|
||||
|
||||
### 8.4. Инвариант «нет дыр» — формальный
|
||||
|
||||
Точка p — «внутренняя дыра», если p ∉ материал, и лучи из p в ≥5 из 8
|
||||
направлений (шаг 45°) пересекают материал в радиусе `2.2 × gridPitch`.
|
||||
Детектор: сетка проб шагом `0.2 × gridPitch` в радиусе `5 × gridPitch` от узла.
|
||||
Ноль внутренних дыр — обязательство для каждого узла каждой сцены сета §13.
|
||||
Уточнение по факту реализации (первая формулировка «окружено кладкой с ≥5 из
|
||||
8 сторон» ложно срабатывала на легитимном полу комнаты в острых внутренних
|
||||
углах — за inset-mitre): детектор проверяет **контрактное покрытие**. Проба p —
|
||||
«дыра», если p ∈ (полоса какого-либо луча узла ∪ веер узла) и p ∉ тело. Сетка
|
||||
проб шагом `0.2 × gridPitch` в радиусе `MITRE_LIMIT × halfDepth + halfDepth` от
|
||||
узла; принадлежность полосе — строго внутри квада (0 ≤ t ≤ длина, |перпендикуляр|
|
||||
< half − ε). Ноль дыр — обязательство для каждого узла каждой сцены сета §13.
|
||||
|
||||
### 8.5. Что не меняется наружно
|
||||
|
||||
@@ -167,12 +182,13 @@
|
||||
исчезли (golden-сцена репро).
|
||||
- **AC3.** Ортогональные стыки одинаковой толщины: попиксельное совпадение с
|
||||
текущими эталонами.
|
||||
- **AC4.** Острый угол 57° со стенами 50/70: сплошная кладка, фаска в пределах
|
||||
`MITRE_LIMIT`.
|
||||
- **AC4.** Острый угол 57° со стенами 50/70: сплошная кладка (перекрытие полос
|
||||
не срезается), свободная часть клина срезана по лимиту узла.
|
||||
- **AC5.** Виртуальный участок в узле не порождает кладку; соседние физические
|
||||
лучи смыкаются веером через него.
|
||||
- **AC6.** Узловая механика не содержит `difference` — проверяется чтением и
|
||||
мутантом на возврат вычитающего слоя.
|
||||
- **AC6.** Единственные вычитания узловой механики — strip-safe фаски §8.2:
|
||||
срез строится уже за вычетом квадов лучей узла. Мутант убирает вычет квадов
|
||||
из среза — детектор обязан покраснеть.
|
||||
- **AC7.** Оба рендерера дают идентичную геометрию узла (один вызов
|
||||
`wallBodiesUnionPath`; смок сверяет пути).
|
||||
- **AC8.** Перф: `smoke_render_perf` в бюджете; large-house без деградации.
|
||||
@@ -206,7 +222,7 @@
|
||||
| `node-fan-outer-only` | веер только с внешней стороны | детектор |
|
||||
| `node-fan-ignores-mitre-limit` | mitre без лимита | юниты веера |
|
||||
| `node-fan-includes-zero-ray` | нулевой луч порождает кладку | юниты + смок |
|
||||
| `node-difference-back` | возврат вычитающего разреза в узел | детектор + AC6 |
|
||||
| `node-cut-not-strip-safe` | срез фаски без вычета квадов лучей | детектор + AC6 |
|
||||
| `hole-detector-blind` | детектор всегда зелёный | самопроверка детектора на заведомо дырявой фикстуре |
|
||||
|
||||
Все юнит-гварды — с пересборкой `test-build` (урок #230/#235).
|
||||
|
||||
Reference in New Issue
Block a user