# Дизайн: типы отверстий — цековка и зенковка (расширение hole)

**Дата:** 2026-05-27
**Статус:** реализовано и проверено (тесты зелёные); на ревью (ревьюер — Codex)

## Цель

Расширить `hole` (простое цилиндрическое, `ksHTBase`) двумя ходовыми типами под крепёж:
**цековка** (`hole_counterbore`, под винт с цилиндрической головкой) и **зенковка**
(`hole_countersink`, под винт с потайной головкой). Через API7 (как базовое отверстие).

## Сигнатуры (рефлексия interop)

```
IHole3D.HoleType = ksHoleTypeEnum:  ksHTBase=0, ksHTCounterbore=1, ksHTCountersinking=2, ksHTConic=4
IHole3D.HoleParameters : IKompasAPIObject  // приводится к типу по HoleType (после установки HoleType)
ISpotfacingHoleParameters (цековка):    SpotfacingDiameter, SpotfacingDepth (мм)
ICountersinkHoleParameters (зенковка):  CountersinkType (ksCountersinkTypeEnum), CountersinkDiameter, CountersinkAngle (°), CountersinkDepth
  ksCountersinkTypeEnum: ksCTDiameterAngle=0, ksCTDepthAngle=1, ksCTDiameterDepth=2
```

## MCP-инструменты (группа Feature)

| Инструмент | Параметры | Поведение |
|---|---|---|
| `hole_counterbore` | `x,y,z`, `diameter`, `spotfaceDiameter`, `spotfaceDepth`, `depth=0`, `throughAll=false` | Отверстие Ø`diameter` + цилиндрическая цековка Ø`spotfaceDiameter`×`spotfaceDepth` сверху. |
| `hole_countersink` | `x,y,z`, `diameter`, `sinkDiameter`, `sinkAngle`, `depth=0`, `throughAll=false` | Отверстие Ø`diameter` + коническая зенковка Ø`sinkDiameter` под углом `sinkAngle`° (тип `ksCTDiameterAngle`). |

**Решения:** конический тип (`ksHTConic`) и резьба (`ShowThread`/`IThread`) — позже. Зенковка задаётся
парой диаметр+угол (`ksCTDiameterAngle`) — самый привычный ввод.

## Реализация

- **`HoleCore` отрефакторен**: добавлены параметры `ksHoleTypeEnum holeType` и `Action<IHole3D>? configure`
  (конфигуратор `HoleParameters` после установки `HoleType`). `HoleAsync` → `ksHTBase, null`.
  Вся остальная логика (размещение через `IHoleDisposal`+`Points3D`, подбор направления по убыли
  объёма, откат «сирот») переиспользуется.
- **`CounterboreHoleAsync`**: валидация (`spotDiameter>diameter`, `spotDepth>0`, finite) →
  `HoleCore(..., ksHTCounterbore, hole => set ISpotfacingHoleParameters)`.
- **`CountersinkHoleAsync`**: валидация (`sinkDiameter>diameter`, `sinkAngle∈(0;180)`, finite) →
  `HoleCore(..., ksHTCountersinking, hole => set ICountersinkHoleParameters: type=ksCTDiameterAngle)`.
- **Инструменты** `hole_counterbore`, `hole_countersink` в `FeatureTools.cs`.

## Тестирование (Integration, `HoleTests`)

- **Цековка**: коробка 40×40×20 → `hole_counterbore(0,0,20, Ø10, spot Ø20×5, throughAll)` →
  удалено = база (π·25·20≈1571) + кольцо цековки (π·75·5≈1178) ≈ 2749 (`±10%`); и
  `removed > базовый цилиндр·1.1` (уширение реально вырезано). ✓
- **Зенковка**: коробка → `hole_countersink(0,0,20, Ø8, sink Ø16, 90°, throughAll)` →
  `removed > база Ø8 (π·16·20≈1005)` и `< база·2` (конус добавил материал, в разумных пределах;
  точный объём зависит от трактовки угла). ✓
