Расчёт площади ВОК для четырёхскатных крыш
Реализовать расчёт площади верхних ограждающих конструкций для типов крыши «Четырёхскатная вальмовая» и «Четырёхскатная шатровая» при прямоугольной форме здания. Формулы зафиксированы в методике; для вальмовой крыши требуется новый исходный параметр «Длина конька», которого нет ни в домене, ни в БД, ни на интерфейсе.
1. Источник (как есть)
Одна из задач второго этапа: доработка методики расчёта: реализация расчёта площади верхних ограждающих конструкций для типов крыши: Односкатная, Четырехскатная вальмовая, Четырехскатная шатровая для прямоугольной форрмы здания.
Задача разбита на две: A — односкатная и B — четырёхскатные (вальмовая и шатровая, этот CR).
2. Разбор
Формулы для обоих типов крыши уже есть в методике — они были вписаны заранее и перенесены
в SDAID вместе с остальным текстом. Реализации нет: MapRoofType в CalcInputModelFactory
на этих типах кидает исключение, а диспетчеры секций
te.attic_wall_area и
te.roof_cover_area знают только плоскую,
двускатную и односкатную крышу.
2.1. Что считаем
Площадь стен чердака по методике для обоих типов равна нулю: у вальмовой и шатровой крыши скаты сходятся со всех сторон, вертикальных фронтонов нет.
| Тип | \(A_{НП.Черд}\) | \(A_{ПК}\) |
|---|---|---|
Четырёхскатная вальмовая (hipped_rect) |
0 | \((L_A + L_{конька})·h_{трап} + L_B·h_{треуг}\) |
Четырёхскатная шатровая (pyramidal_rect) |
0 | \(L_A·h^A_{треуг} + L_B·h^B_{треуг}\) |
где \(h_{трап} = \sqrt{(H-z_{ВП})^2 + (L_B/2)^2}\), \(h_{треуг} = \sqrt{(H-z_{ВП})^2 + ((L_A-L_{конька})/2)^2}\), \(h^A_{треуг} = \sqrt{(H-z_{ВП})^2 + (L_B/2)^2}\), \(h^B_{треуг} = \sqrt{(H-z_{ВП})^2 + (L_A/2)^2}\).
Шатровая — вырожденный случай вальмовой при \(L_{конька} = 0\): подставив ноль в формулу вальмовой, получаем формулу шатровой. Отдельными ветками расчёта они остаются — тип задан справочником, — но это объясняет, почему незаполненный конёк у вальмовой крыши опасен: расчёт молча даст площадь шатровой — отсюда правило обязательности ниже.
2.2. Как различаются вальмовая и шатровая
В загруженном из АИС ОИА ПЭО справочнике типов крыш для них заведены отдельные записи:
hipped — четырёхскатная вальмовая, pyramidal — четырёхскатная шатровая. Тип расчёта
определяется кодом записи напрямую, как для плоской, двускатной и односкатной крыши.
Длина конька — исходный параметр формулы вальмовой крыши, а не способ определить тип.
2.3. Новый параметр «Длина конька»
Параметр не ведёся в АИС ОИА ПЭО. Его надо добавить в характеристики верхних ограждающих конструкций, в сущность ВОК:
/// <summary>Длина конька, м</summary>
[DomainField(
Alias = "ridge_length_m",
RequiredForCalc = "Да, если Тип крыши.Код = \"hipped\"",
Unit = "м",
Range = "вещественное, 0 < L_конька < Размер по габариту A"
)]
public decimal RidgeLengthM { get; set; }
Он будет заполняться пользователем в Сервисе, импорт из АИС его не должен затирать.
Атрибут добавлен в спецификацию сущности этим CR. Как он ложится на структуру БД, read-модель и контракты — в разделе Blast radius.
2.4. Правило валидации длины конька
Правило одно, внесено в методику — раздел «Правила валидации» секции te.roof_cover_area: для вальмовой крыши \(0 < L_{конька} < L_A\). Место выбрано по использованию: длина конька входит только в эту секцию, смежная te.attic_wall_area для четырёхскатных крыш даёт ноль.
Обоснование границ: верхняя — из наклонной высоты торцевого ската \(h_{треуг}=\sqrt{(H-z_{ВП})^2 + ((L_A-L_{конька})/2)^2}\), при \(L_{конька} = L_A\) торцевые скаты вырождаются в линию. Сторона сравнения — \(L_A\), а не \(\max(L_A, L_B)\): конёк входит в формулу как слагаемое и вычитаемое именно к \(L_A\). Нижняя граница строгая, поэтому незаполненное значение нельзя подставлять нулём: при нулевом коньке формула вальмовой крыши вырождается в формулу шатровой и вернула бы площадь крыши другого типа.
2.5. Открытые вопросы
- OQ-1. Контрольные примеры — по одному на вальмовую и шатровую крышу. Значения предоставляет заказчик: расчёт контрольных чисел тем же алгоритмом, который проверяется, ничего не доказывает.
Прежняя запись справочника «Четырехскатная» (tr300), если она осталась и на неё ссылаются
модели, остаётся типом крыши, не поддержанным методикой, — как и tr400 «Двускатная без
нижнего перекрытия». Ни то, ни другое в объём этого CR не входит.
3. Blast radius
В отличие от CR по односкатной крыше, здесь появляется новый исходный параметр, поэтому
правка сквозная — от структуры БД до формы ввода. Ниже — фактическая цепочка,
прослеженная по коду на примере соседнего атрибута «Уровень верхнего перекрытия»
(UpperFloorLevelM), который проходит ровно те же слои.
3.1. Спецификация
| Документ | Правка |
|---|---|
| ВОК | новый атрибут «Длина конька, м» в классе сущности — таблица свойств и диаграмма связей строятся по нему |
| te.roof_cover_area | правила валидации длины конька — внесены; источник данных для \(L_{конька}\) — атрибут сущности ВОК |
| te.attic_wall_area | правила валидации: перечень типов крыши |
| Модель расчёта CalcModel | блок roof модели входных данных: новое поле ridgeLengthM — без него параметр не доедет до расчёта |
| Маппинг домен → InputModel (ТЭ) | соответствие Roof.RidgeLength ← «ВОК. Длина конька, м» в секции TeInputSection.Roof |
| Тип крыши | состав справочника: записи hipped и pyramidal загружены из АИС; правок не требует, фиксируется как факт |
| Вкладка "Верхние ограждающие конструкции | поле «Длина конька, м» в описании полей вкладки и в макете экрана — видимое только для вальмовой крыши |
3.2. База данных
CmRoofModelEntity— свойствоRidgeLengthM(decimal?) и сеттер по образцуSetUpperFloorLevelM; копирование в методе клонирования модели.CmRoofModelEntityConfiguration—builder.Property(...).HasComment(...).- Миграция EF в
Ntr.Infrastructure/Migrations: колонкаridge_length_mтипаnumeric, nullable, в таблицеntr.cm_roof_models. Данных не переносим: у существующих моделей конёк не заполнен. Infrastructure.Read/NtrModels/CmRoofModel+ конфигурация read-контекста — read-модель ведётся отдельно от доменной.
3.3. API и контракты
RoofModelDetails(модель ответа) иRoofModelDetailsDtoвConsumptionModelDtos— новое поле.GetConsumptionModelForEditQueryHandler— проекция поля в ответ.CreateConsumptionModelCommandHandler,ApplyConsumptionModelEditCommandHandler,ConsumptionModelService— запись значения в сущность.AisToNtrImportService— правок не требует: в выгрузке АИС длины конька нет, импорт поле не трогает.- Swagger-контракт меняется ⇒ требуется перегенерация клиента фронтенда.
3.4. Расчёт
Цепочка передачи параметра до формулы: атрибут сущности ВОК → колонка БД → DTO ответа
и команды → InputModel.roof.ridgeLengthM → RoofTeInput.RidgeLength → калькулятор
секции te.roof_cover_area. Разрыв в любом звене оставит расчёт с пустым коньком,
то есть с ошибкой валидации.
RoofTeInput— полеRidgeLength; сборка входной модели вCalcInputModelFactory.CalcInputModelFactory— проброс длины конька и сопоставление кодовhippedиpyramidalс типами расчёта.RoofType— новые значения перечисления.RoofCoverAreaCalculator— веткиhipped_rectиpyramidal_rect;AtticWallAreaCalculator— обе ветки дают ноль.- Валидаторы обеих секций — допуск новых типов крыши и правило по \(L_{конька}\).
3.5. Интерфейс
roof.util.ts— контрол, заполнение при загрузке модели, дескриптор поля формы, сборка payload. Поле показывается только для четырёхскатной крыши — по образцу полей, зависящих от «Наличия чердака».- Сгенерированный клиент
roofModelDetails.ts— после перегенерации по swagger. - Отображение атрибута в карточке модели в режиме просмотра.
3.6. Тесты
- Контрольные примеры на вальмовую и шатровую крышу в
src/Ntr.Calc.Tests(значения — OQ-1).
4. План
- Правки спецификации по таблице blast radius; в изменённых секциях проставить
StatusиCommentsсо ссылкой на этот CR. - Домен и БД: атрибут, конфигурация, миграция, read-модель.
- API: контракты, обработчики команд и запросов; перегенерация клиента.
- UI: поле на форме и в карточке модели.
- Расчёт: типы крыши, ветки калькуляторов, валидаторы, сопоставление кода справочника.
- Контрольные примеры (значения предоставляет заказчик).
- Зафиксировать «Итог».
Шаги 2–5 разумно вести снизу вверх (домен → API → UI), чтобы контракт менялся один раз.
5. Acceptance criteria
- AC-1. Контрольные примеры на вальмовую и шатровую крышу в
src/Ntr.Calc.Testsпроходят: расчёт завершается со статусомSuccess, значения \(A_{НП.Черд}\), \(A_{ПК}\) и \(A_{ВОК}\) совпадают с контрольными. - AC-2. В карточке модели на вкладке верхних ограждающих конструкций можно ввести длину конька; значение сохраняется и после перезагрузки страницы отображается прежним.
- AC-3. Модель потребления с четырёхскатной крышей рассчитывается из интерфейса и не падает с ошибкой «Необрабатываемый тип крыши».
- AC-4. В журнале расчёта виден выбранный вариант методики —
hipped_rectилиpyramidal_rect. - AC-5. Повторный импорт данных из АИС ОИА ПЭО не затирает введённую длину конька.
- AC-6. Поведение моделей с плоской, двускатной и односкатной крышей не изменилось: контрольные примеры 1–4 продолжают проходить.
6. Итог
—
Структурные связи
Использует
- Документ 2. Модель расчёта CalcModel
- Документ Маппинг доменных данных → InputModel (ТЭ)
- Доменная сущность ВОК
- Доменная сущность Тип крыши
- Инфраструктура Импорт данных из АИС
- Компонент Вкладка "Верхние ограждающие конструкции
- Прикладной сервис Теплотехнический расчёт
Связанные артефакты
Документы
- Документ 2. Модель расчёта CalcModel
- Документ Маппинг доменных данных → InputModel (ТЭ)
- Доменная сущность ВОК
- Доменная сущность Тип крыши
- Компонент Вкладка "Верхние ограждающие конструкции