ADN Open CIS
Сообщество программистов Autodesk в СНГ

27/06/2019

Как установить положение камеры в 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}):

Код - JavaScript: [Выделить]
  1. {
  2.   "viewport": {
  3.     "name": "",
  4.     "eye": [
  5.       -14.870469093323,
  6.       36.571562767029,
  7.       -1.2129259109497
  8.     ],
  9.     "target": [
  10.       -14.770469665527,
  11.       36.571967124939,
  12.       -1.2129259109497
  13.     ],
  14.     "up": [
  15.       0,
  16.       0,
  17.       1
  18.     ],
  19.     "worldUpVector": [
  20.       0,
  21.       0,
  22.       1
  23.     ],
  24.     "pivotPoint": [
  25.       -14.770469665527,
  26.       36.571967124939,
  27.       -1.2129259109497
  28.     ],
  29.     "distanceToOrbit": 0.10000024532334,
  30.     "aspectRatio": 3.1789297658863,
  31.     "projection": "perspective",
  32.     "isOrthographic": false,
  33.     "fieldOfView": 90.68087674208
  34.   }
  35. }

2. Получаем смещение текущей загруженной модели (Примечание. Viewer использует его для регулирования позиций загруженных моделей чтобы избежать проблем с точностью представления реальных чисел и проблем c определением видимости элементов, см Z-буфферизации, Z-fighting) из свойства viewer.model.getData().globalOffset, пример результата:

Код - JavaScript: [Выделить]
  1. {
  2.   "x": -0.253891,
  3.   "y": -45.556179,
  4.   "z": 6.134186
  5. }

3. Вычитаем globalOffset из векторов направления и позиции камеры Viewer-а

Код - JavaScript: [Выделить]
  1. const state = viewer.getState({ viewport: true });
  2. const globalOffset = viewer.model.getData().globalOffset
  3.  
  4. const currentTarget = new THREE.Vector3().fromArray( state.viewport.target );
  5. // {x: -14.770469665527344, y: 36.571967124938965, z: -1.212925910949707}
  6.  
  7. const currentPosition = new THREE.Vector3().fromArray( state.viewport.eye );
  8. // {x: -14.870469093322754, y: 36.57156276702881, z: -1.212925910949707}
  9.  
  10. const originTarget = currentTarget.clone().add( globalOffset );
  11. // {x: -15.02436066552734, y: -8.984211875061035, z: 4.921260089050291}
  12.  
  13. const originPosition = currentPosition.clone().add( globalOffset );
  14. // {x: -15.12436009332275, y: -8.984616232971192, z: 4.921260089050291}

На стороне Revit:

Здесь мы используем перспективные виды Revit, управляя crop region-ом:

Код - C#: [Выделить]
  1. //const currentTarget = new THREE.Vector3().fromArray( state.viewport.target );
  2. // {x: -14.770469665527344, y: 36.571967124938965, z: -1.212925910949707}
  3.  
  4. //const currentPosition = new THREE.Vector3().fromArray( state.viewport.eye );
  5. // {x: -14.870469093322754, y: 36.57156276702881, z: -1.212925910949707}
  6.  
  7. //const originTarget = currentTarget.clone().add( globalOffset );
  8. // {x: -15.02436066552734, y: -8.984211875061035, z: 4.921260089050291}
  9.  
  10. //const originPosition = currentPosition.clone().add( globalOffset );
  11. // {x: -15.12436009332275, y: -8.984616232971192, z: 4.921260089050291}
  12.  
  13. //const up = new THREE.Vector3().fromArray( state.viewport.up );
  14. // {x: 0, y: 0, z: 1}
  15.  
  16. using(var trans = new Transaction(this.Document, "Map LMV Camera"))
  17. {
  18.                 try
  19.                 {
  20.                     if(trans.Start() == TransactionStatus.Started)
  21.                     {
  22.                                    IEnumerable<ViewFamilyType> viewFamilyTypes = from elem in new FilteredElementCollector(this.Document).OfClass(typeof(ViewFamilyType))
  23.                                     let type = elem as ViewFamilyType
  24.                                     where type.ViewFamily == ViewFamily.ThreeDimensional
  25.                                     select type;
  26.                               
  27.                                                    // Create a new Perspective View3D
  28.                                                    View3D view3D = View3D.CreatePerspective(this.Document, viewFamilyTypes.First().Id);
  29.                                                    Random rnd = new Random();
  30.                                                   view3D.Name = string.Format("Camera{0}", rnd.Next()) ;
  31.                                                   // By default, the 3D view uses a default orientation.
  32.                                                   // Change the orientation by creating and setting a ViewOrientation3D
  33.                                                   var position = new XYZ(-15.12436009332275, -8.984616232971192, 4.921260089050291);
  34.                                                   var up = new XYZ(0,0,1);
  35.                                                   var target = new XYZ(-15.02436066552734, -8.984211875061035, 4.921260089050291);
  36.                                                   var sightDir = target.Subtract( position ).Normalize();
  37.                                               
  38.                                                   var orientation = new ViewOrientation3D( position, up, sightDir );
  39.                                                   view3D.SetOrientation( orientation );
  40.                               
  41.                                                   // turn off the far clip plane with standard parameter API
  42.                                                   Parameter farClip = view3D.LookupParameter("Far Clip Active");
  43.                                                   farClip.Set(0);
  44.                                   
  45.                                                  Parameter cropRegionVisible = view3D.LookupParameter("Crop Region Visible");
  46.                                                  cropRegionVisible.Set(1);
  47.                                   
  48.                                                  Parameter cropView = view3D.LookupParameter("Crop View");
  49.                                                  cropView.Set(1);
  50.                                   
  51.                                                  trans.Commit();
  52.                     }         
  53.                 }
  54.                 catch(Exception ex)
  55.                 {
  56.                                trans.RollBack();
  57.                                TaskDialog.Show("Revit", ex.Message);
  58.                 }
  59. }

Результат выполнения кода:

Используя значения углов обзора, фокусного расстояния, размера кадра и изображения, приведенных выше получаем:

Требуемая ширина: 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