# 25.12 Rotate / Switch Ortho Problems Report

Отчет составлен по содержимому чата и локальным изменениям кода в проекте.
Цель: зафиксировать весь путь расследования проблем с вращением (ось/pivot)
и прыжками камеры при переключении ортографической и перспективной проекции.

---

## 1. Подробное описание проблемы, наблюдений, логов и взаимосвязей

### 1.1 Контекст и среда
- Сцены очень крупные (километры), много LAS облаков, иногда GLB модели.
- Рабочий сценарий: уйти далеко, вернуться к объекту, переключать ortho/persp, вращать камеру.
- Пользователь каждый тест делает с очисткой кэша браузера. Сервер не перезапускается.
- На «свежем» состоянии проблемы часто не проявляются сразу, но появляются спустя время/навигацию.

### 1.2 Симптомы (что видит пользователь)
1) **Смещение оси вращения (pivot drift).**
   - Вращение идет вокруг точки, которая не совпадает с курсором или целевым объектом.
   - Часто ощущается, что точка вращения «за камерой» или сильно в стороне.
   - В ortho проявляется чаще, но бывает и в perspective.
   - Иногда исчезает после переключения в perspective или после фокуса (двойной клик).

2) **Прыжки камеры при переключении ortho <-> perspective.**
   - При переключении камера уезжает назад или в сторону на 50–200+ метров.
   - После прыжка новая дистанция становится «новой нормой» для следующих переключений.
   - Особенно часто при переключении из ortho в perspective.

3) **Клиппинг (статические отсечки) в ortho.**
   - Периодически появляется «плоскость отсечения», которая не зависит от зума.
   - Отсечка исчезает при смене ракурса/переключении проекции, но может вернуться.

4) **Нестабильный зум (скачки шага).**
   - После сильного отлета зум начинает «пропускать шаги».
   - Приближение становится грубым: следующая позиция уже «за объектом».

### 1.3 Наблюдения (устойчивые повторения)
- Проблемы чаще всего возникают после **сильного отлета** и перемещения на большое расстояние.
- При аккуратной локальной работе (вокруг одного объекта) поведение обычно стабильнее.
- Переключение в perspective и небольшой «полет» иногда стабилизируют pivot.
- После double-click фокусировки проблемы временно исчезают.

### 1.4 Логи, которые использовались
В процессе добавлены и использовались флаги:
- `window.__dcProjDebug = true`
- `window.__dcPivotDebug = true`
- `window.__dcAllowOffsetEye = true` (опционально, для диагностики)

Типовые лог-сообщения:
- Проекции: `[dc-proj] persp->ortho`, `[dc-proj] ortho->persp`, `proj-switch(before/after)`
- Пивот: `[dc-pivot] start`, `[dc-pivot] start-clamp`, `[dc-pivot] ortho-pivot`, `[dc-pivot] persp-pick`, `[dc-pivot] ortho-eye-normalize`

Что замечено по логам:
- В ortho часто фиксируется **несоответствие между eyeLookDist и orthoScale** (orthoScale намного больше).
- В некоторых логах `pickDist`/`rayDist` сильно отличаются от `eyeLookDist`.
- Были ситуации, когда `pivotPos == look`, но ощущение вращения все равно «кривое»,
  значит проблема не только в выборе pivot, а в состоянии камеры (eye/scale).

### 1.5 Взаимосвязи и гипотезы
Основные гипотезы, подтвержденные частично логами и наблюдениями:
- **Проблемы накопительные**: чем больше дальних перемещений и масштаба, тем выше шанс сломаться.
- **Пивот в ortho** при выборе через pick/ray нестабилен в больших сценах.
- **Сильные отлеты** приводят к разрыву между `orthoScale` и `eyeLookDist`, что искажает ось вращения.
- **Переключение проекций** использует параметры, которые не всегда согласованы с текущим состоянием камеры.

---

## 2. Подробное описание всех попыток исправления

Ниже приведены все попытки с указанием:
где делали, что меняли, зачем, ожидаемый результат и фактический результат.

### Попытка 1. Настройки клиппинга в UI (viewport)
**Где:** UI блок `Viewport` (инспектор).  
**Что сделали:** добавили поля для клиппинга (perspective/ortho), позже min/max.  
**Зачем:** пользователь видел слишком ранние отсечки и хотел управлять дистанцией.  
**Ожидание:** контроль near/far клиппинга решит отсечки и приблизит камеру.  
**Факт:** в perspective стало предсказуемее, в ortho появились «статические» отсечки,
которые не всегда зависели от камеры. Проблема клиппинга осталась.

### Попытка 2. Принудительный near/far (0.01 / 1e9)
**Где:** параметры камеры.  
**Зачем:** исключить влияние near/far.  
**Ожидание:** клиппинг исчезнет.  
**Факт:** не помогло, отсечки остались.

### Попытка 3. Включение логов и сбор метрик
**Где:** консольный дебаг, далее встроенные логи.  
**Что:** добавлены `[dc-proj]` и `[dc-pivot]` логи.  
**Зачем:** видеть dist, orthoScale, pickDist, rayDist.  
**Ожидание:** найти связь между параметрами и рывками/пивотом.  
**Факт:** выявлены несоответствия scale/dist и роль сильных отлетов, но без прямого фикса.

### Попытка 4. Форк core-камеры в локальный файл
**Где:** `frontend/lib/dc-camera-context.es.js`  
**Что:** из minified xeokit сделали локальную «контекстную» версию для правок.  
**Зачем:** исправлять первоисточник, а не обертки.  
**Ожидание:** полный контроль над Camera/Ortho/Perspective.  
**Факт:** сначала ошибки сборки (duplicate identifier, lookAtMat4v undefined),
после коррекции файл заработал и стал основным местом правок.

### Попытка 5. Удаление обертки проекций
**Где:** `frontend/dcViewer.js`  
**Что:** удален `projectionSync` (обертка синхронизации проекций).  
**Зачем:** убрать внешние корректировки, которые могут конфликтовать.  
**Ожидание:** меньше неожиданных прыжков.  
**Факт:** источник конфликтов убран, но прыжки и pivot drift остались.

### Попытка 6. Пересчет ortho/persp в Camera.projection
**Где:** `frontend/lib/dc-camera-context.es.js` (Camera.projection setter)  
**Что:**\n
- `persp -> ortho`: масштаб берется из `dist` и `fov`  
- `ortho -> persp`: дистанция берется из `orthoScale` и `fov`  
- убраны расчеты на основе `rayDist`  
**Зачем:** сделать переключение более детерминированным.  
**Ожидание:** стабильная дистанция при переключениях.  
**Факт:** иногда лучше, но рывки оставались, особенно после большого зума.

### Попытка 7. Отключение offsetEyeFromLook
**Где:** `frontend/lib/dc-camera-context.es.js`  
**Что:** `offsetEyeFromLook` теперь false по умолчанию, включается через флаг `__dcAllowOffsetEye`.  
**Зачем:** offset подозревался как источник смещения оси вращения.  
**Ожидание:** pivot станет стабильнее.  
**Факт:** стало немного стабильнее, но проблема не исчезла.

### Попытка 8. Clamp pivot по dot/ratio
**Где:** `PivotController.startPivot`  
**Что:** если pivotDist/eyeLookDist слишком большой или направление не совпадает,
pivot принудительно сбрасывается на `look`.  
**Зачем:** исключить pivot за камерой.  
**Ожидание:** уменьшение случаев «кривой» оси.  
**Факт:** часть экстремальных случаев ушла, но проблема оставалась.

### Попытка 9. Эвристики ortho pick pivot
**Где:** обработчик mouse/touch для pivot в `dc-camera-context.es.js`  
**Что:** pick pivot принимается только при нормальных dot/ratio и пределах `rayDist`.  
**Зачем:** в ortho pick часто уводил pivot в неверное место.  
**Ожидание:** меньше смещений оси.  
**Факт:** поведение было нестабильным, в некоторых случаях хуже.

### Попытка 10. Ortho eye normalize
**Где:** `PivotController.startPivot`  
**Что:** если `orthoScale >> eyeLookDist`, camera.eye отодвигается вдоль вида
на `max(eyeLookDist, orthoScale)`.  
**Зачем:** уменьшить расхождение между масштабом и дистанцией камеры.  
**Ожидание:** стабилизация оси вращения в ortho после сильного зума.  
**Факт:** результаты неоднозначные, иногда хуже.

### Попытка 11. Полное отключение pick pivot в ortho (последняя правка)
**Где:** mouse/touch обработчики pivot в `dc-camera-context.es.js`  
**Что:** при ortho pivot всегда `camera.look`, pick/ray не используются.  
**Зачем:** убрать нестабильность pick pivot.  
**Ожидание:** стабильная ось вращения в ortho.  
**Факт:** требуется повторный тест после этой правки.

### Попытка 12. Жесткая фиксация `look` и движение `eye` вдоль направления
**Где:** `Camera.projection` setter  
**Что:** при переключении проекций `look` фиксируется,
`eye` пересчитывается только по направлению вида (без боковых смещений).  
**Зачем:** убрать скачки в сторону/назад при ortho <-> persp.  
**Ожидание:** переключение без прыжков по позиции.  
**Факт:** требуется повторный тест после этой правки.

### Попытка 13. Расширенные логи
**Где:** `dc-camera-context.es.js`  
**Что:** добавлены детальные логи `[dc-proj]` и `[dc-pivot]`.  
**Зачем:** фиксировать реальные параметры во время рывков.  
**Ожидание:** получить воспроизводимые метрики для анализа.  
**Факт:** помогло подтвердить связь с сильным зумом, но без полного решения.

---

## 3. Итоговое состояние на момент отчета

Актуальные изменения в форке:
- `frontend/lib/dc-camera-context.es.js`:
  - упрощен пересчет ortho/persp;
  - `offsetEyeFromLook` по умолчанию false;
  - pivot clamp при подозрительном pivot;
  - `ortho-eye-normalize` (эксперимент);
  - **в ortho pivot всегда `look`**, pick/ray игнорируется (последняя правка);
  - логи `__dcProjDebug` и `__dcPivotDebug`.
- `frontend/dcViewer.js`:
  - удалена обертка `projectionSync`.

Состояние проблемы:
- после ряда правок поведение часто становится лучше на короткой дистанции,
  но при сильных отлетах проблема возвращается.
- основной подозреваемый: накопление состояния в камере
  + разрыв между `orthoScale` и `eyeLookDist`
  + нежелательные pivot‑решения в ortho.

---

## 4. Что требуется для следующей итерации
1) Свежий тест после последних правок (без длительных старых сессий).  
2) Логи:
   - `window.__dcProjDebug = true`
   - `window.__dcPivotDebug = true`
3) Сценарий:
   - сильно отлететь,
   - вернуться к объекту,
   - вращать в ortho,
   - переключить ortho/persp.

Если вновь поймается «кривая ось» или «скачок дистанции»,
лог должен сопровождать момент, чтобы анализировать разницу
между `eyeLookDist`, `orthoScale`, `pivotDist`, `pickDist`, `rayDist`.

