Как установить положение камеры в Revit из Forge Viewer-а
Недавно ко мне пришёл запрос от одного из клиентов, использующих Forge Viewer. Он хотел перенести позицию камеры из Viewer-а обратно в Revit с помощью Revit API, что я успешно и реализовал. Перед тем как продолжить, Вам следует знать следующее о том, как Revit работает с камерой:
- Камера по умолчанию имеет угол обзора примерно 50 градусов, фокусное расстояние 38,6 мм, размер кадра 36 мм
- Размер изображения при рендеринге - 6 дюймов
- Для изменения угла обзора в Revit API, нужно работать с CropBox объекта View3D, прямого пути изменить его нет
- Камера в Forge Viewer более широкоформатная, по сравнению с камерой в Revit
Примечание: Параметры камеры подобраны методом проб и ошибок, значения выше - примерные
Итак, приступим: (примечание - шаги ниже приведены для создания вида в перспективе, не ортогонального)
Данные из Forge Viewer-а:
1. Получим фокусное расстояние (методом Viewer3D.getFocalLength()), направление, позицию и вертикальное направление камеры. Результат вызова метода Viewer3D.getState({viewport: true}):
- {
- "viewport": {
- "name": "",
- "eye": [
- -14.870469093323,
- 36.571562767029,
- -1.2129259109497
- ],
- "target": [
- -14.770469665527,
- 36.571967124939,
- -1.2129259109497
- ],
- "up": [
- 0,
- 0,
- 1
- ],
- "worldUpVector": [
- 0,
- 0,
- 1
- ],
- "pivotPoint": [
- -14.770469665527,
- 36.571967124939,
- -1.2129259109497
- ],
- "distanceToOrbit": 0.10000024532334,
- "aspectRatio": 3.1789297658863,
- "projection": "perspective",
- "isOrthographic": false,
- "fieldOfView": 90.68087674208
- }
- }
2. Получаем смещение текущей загруженной модели (Примечание. Viewer использует его для регулирования позиций загруженных моделей чтобы избежать проблем с точностью представления реальных чисел и проблем c определением видимости элементов, см Z-буфферизации, Z-fighting) из свойства viewer.model.getData().globalOffset, пример результата:
- {
- "x": -0.253891,
- "y": -45.556179,
- "z": 6.134186
- }
3. Вычитаем globalOffset из векторов направления и позиции камеры Viewer-а
- const state = viewer.getState({ viewport: true });
- const globalOffset = viewer.model.getData().globalOffset
- const currentTarget = new THREE.Vector3().fromArray( state.viewport.target );
- // {x: -14.770469665527344, y: 36.571967124938965, z: -1.212925910949707}
- const currentPosition = new THREE.Vector3().fromArray( state.viewport.eye );
- // {x: -14.870469093322754, y: 36.57156276702881, z: -1.212925910949707}
- const originTarget = currentTarget.clone().add( globalOffset );
- // {x: -15.02436066552734, y: -8.984211875061035, z: 4.921260089050291}
- const originPosition = currentPosition.clone().add( globalOffset );
- // {x: -15.12436009332275, y: -8.984616232971192, z: 4.921260089050291}
На стороне Revit:
Здесь мы используем перспективные виды Revit, управляя crop region-ом:
- //const currentTarget = new THREE.Vector3().fromArray( state.viewport.target );
- // {x: -14.770469665527344, y: 36.571967124938965, z: -1.212925910949707}
- //const currentPosition = new THREE.Vector3().fromArray( state.viewport.eye );
- // {x: -14.870469093322754, y: 36.57156276702881, z: -1.212925910949707}
- //const originTarget = currentTarget.clone().add( globalOffset );
- // {x: -15.02436066552734, y: -8.984211875061035, z: 4.921260089050291}
- //const originPosition = currentPosition.clone().add( globalOffset );
- // {x: -15.12436009332275, y: -8.984616232971192, z: 4.921260089050291}
- //const up = new THREE.Vector3().fromArray( state.viewport.up );
- // {x: 0, y: 0, z: 1}
- using(var trans = new Transaction(this.Document, "Map LMV Camera"))
- {
- try
- {
- if(trans.Start() == TransactionStatus.Started)
- {
- IEnumerable<ViewFamilyType> viewFamilyTypes = from elem in new FilteredElementCollector(this.Document).OfClass(typeof(ViewFamilyType))
- let type = elem as ViewFamilyType
- where type.ViewFamily == ViewFamily.ThreeDimensional
- select type;
- // Create a new Perspective View3D
- View3D view3D = View3D.CreatePerspective(this.Document, viewFamilyTypes.First().Id);
- Random rnd = new Random();
- view3D.Name = string.Format("Camera{0}", rnd.Next()) ;
- // By default, the 3D view uses a default orientation.
- // Change the orientation by creating and setting a ViewOrientation3D
- var position = new XYZ(-15.12436009332275, -8.984616232971192, 4.921260089050291);
- var up = new XYZ(0,0,1);
- var target = new XYZ(-15.02436066552734, -8.984211875061035, 4.921260089050291);
- var sightDir = target.Subtract( position ).Normalize();
- var orientation = new ViewOrientation3D( position, up, sightDir );
- view3D.SetOrientation( orientation );
- // turn off the far clip plane with standard parameter API
- Parameter farClip = view3D.LookupParameter("Far Clip Active");
- farClip.Set(0);
- Parameter cropRegionVisible = view3D.LookupParameter("Crop Region Visible");
- cropRegionVisible.Set(1);
- Parameter cropView = view3D.LookupParameter("Crop View");
- cropView.Set(1);
- trans.Commit();
- }
- }
- catch(Exception ex)
- {
- trans.RollBack();
- TaskDialog.Show("Revit", ex.Message);
- }
- }
Результат выполнения кода:
Используя значения углов обзора, фокусного расстояния, размера кадра и изображения, приведенных выше получаем:
Требуемая ширина: 6" x 38.6 / фокусное расстояние камеры Viewer, 6" x 38.6 / 12 = 19.3" = 490.22 mm
Требуемая высота: 19.3" x пропорции широкоформатной камеры, 19.3" x 2/3 = 12.87" = 326.898 mm
Устанавливаем область подрезки с помощью UI:
Итоговый результат:
Источник: https://forge.autodesk.com/blog/map-forge-viewer-camera-back-revit
Обсуждение: http://adn-cis.org/forum/index.php?topic=
Опубликовано 27.06.2019