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

27/06/2019

Получаем данные модели здания с помощью Model Derivative API

Model Derivative API позволяет получать данные AEC (Architecture, Engineering, Construction) - модели здания из файла Revit-а, такие как уровни, оси, виды, стадии, связанные документы и т.д. Forge Viewer также предоставляет соответствующие методы.

Model Derivative API получает общие данные исходной модели - дерево иерархии элементов, свойства объектов, их геометрию. В большинстве случаев, этих данных достаточно при работе с Forge Viewer. В то время как в файле Revit есть специфичная для модели здания информация, которую зачастую хочется интегрировать в приложение, такая как виды, оси, уровни, стадии, связанные документы и т.д.

У нас уже есть несколько решений подобных проблем:

- Уровень по имени узла - решение ищет узлы в дереве модели с именем level, и изолирует объекты с одинаковым значением уровня

- Оси сетки на основе обобщённых моделей -  решение создает обобщённые модели для визуализации осей сетки в Forge Viewer

С определенного релиза, Model Derivative API имеет возможность получать данные AEC, а Forge Viewer предоставляет соответствующие методы. Эти данные не доступны в кэше по умолчанию после загрузки модели во Viewer. Соответственно, первый шаг - вызвать метод downloadAecModelData документа viewer-а, далее методом getAecModelData получить необходимую информацию, примерно следующего вида:

Большая часть данных вполне понятна по именам в схеме.

grids: вся информация об осях сетки основного и связанных документов. Свойство document каждой оси сетки показывает, в какой модели содержится эта ось. Одна ось может иметь множество сегментов, каждый сегмент содержит начальную и конечную точку. Похоже, что пока нет признака, определяющего, на каком уровне расположена ось, все оси находятся в одной плоскости.

levelOccluderIds: id всех перекрытий и потолков. К сожалению, не показывает, какие id к каким уровням относятся.

Levels: все доступные уровни. Показывает высоту уровней относительно базовой точки проекта, height здесь - расстояние до следующего уровня, name - имя уровня. Так же показывает, является ли этаж уровнем земли или нет.

Phases: Все непустые стадии проекта, т.е. стадии, которые присутствуют в элементах проекта Revit.

Viewports: все видовые экраны листов, включая данные камер, секущих плоскостей, guid-ов листов, на которых они размещены и т.д. Массив cameraOrientation содержит данные ориентации камеры array[0]-array[2] - направление камеры (forward direction vector), array[3]-array[5] - направление вверх (camera up vector), array[6]-array[8] - координаты позиции камеры. viewportPosition - массив, содержащий информацию о расположении видового экрана на листе. array[0]-array[2] - нижний левый угол видового экрана, array[3]-array[5] - его правый верхний угол.

Код ниже отрисовывает линию сетки, круг и текст с помощью Three.js:

Код - JavaScript: [Выделить]
  1. //первый этап: загружаем AEC-данные методом downloadAecModelData
  2. function onDocumentLoadSuccess(doc) {
  3.  
  4.             var viewables = viewerApp1.bubble.search({'type':'geometry'});
  5.             if (viewables.length === 0) {
  6.                 console.error('Document contains no viewables.');
  7.                 return;
  8.             }
  9.            
  10.            // загрузка данные AEC
  11.             doc.downloadAecModelData()
  12.  
  13.             //....
  14. }

Extension для создания текста оси сетки:

Код - JavaScript: [Выделить]
  1. import { Font, TextGeometry} from './threejs-full-es6/builds/Three.es.js'
  2. import FontJson from './helvetiker_bold.typeface.json'
  3.  
  4. export default class TextExtension
  5.   extends Autodesk.Viewing.Extension {
  6.  
  7.   /////////////////////////////////////////////////////////
  8.   // Adds a color material to the viewer
  9.   //
  10.   /////////////////////////////////////////////////////////
  11.   constructor (viewer, options) {
  12.  
  13.     super()
  14.  
  15.     this.viewer = viewer
  16.   }
  17.  
  18.   load () {
  19.  
  20.     return true
  21.   }
  22.  
  23.   unload () {
  24.  
  25.     return true
  26.   }
  27.  
  28.   /////////////////////////////////////////////////////////
  29.   // Adds a color material to the viewer
  30.   //
  31.   /////////////////////////////////////////////////////////
  32.   createColorMaterial (color) {
  33.  
  34.     const material = new THREE.MeshPhongMaterial({
  35.       specular: new THREE.Color(color),
  36.       side: THREE.DoubleSide,
  37.       reflectivity: 0.0,
  38.       color
  39.     })
  40.  
  41.     const materials = this.viewer.impl.getMaterials()
  42.  
  43.     materials.addMaterial(
  44.       color.toString(),
  45.       material,
  46.       true)
  47.  
  48.     return material
  49.   }
  50.  
  51.   /////////////////////////////////////////////////////////
  52.   // Wraps TextGeometry object and adds a new mesh to
  53.   // the scene
  54.   /////////////////////////////////////////////////////////
  55.   createText (params) {
  56.    
  57.     params.font = new Font(FontJson)
  58.     const geometry = new TextGeometry(params.text,params)
  59.  
  60.     const material = this.createColorMaterial(
  61.       params.color)
  62.  
  63.     const text = new THREE.Mesh(
  64.       geometry , material)
  65.  
  66.     text.position.set(
  67.       params.position.x,
  68.       params.position.y,
  69.       params.position.z)
  70.  
  71.     this.viewer.impl.scene.add(text)
  72.  
  73.     this.viewer.impl.sceneUpdated(true)
  74.   }
  75.  
  76. }
  77.  
  78. Autodesk.Viewing.theExtensionManager.registerExtension(
  79.   ' ', TextExtension)

Отрисовываем оси сетки:

Код - JavaScript: [Выделить]
  1. import './Viewing.Extension.Text'
  2.  
  3. // ...
  4.  
  5. viewer.loadExtension('Viewing.Extension.Text').then((extension) => {
  6.     drawGrid()
  7. })
  8.  
  9. function drawGrid(){
  10.  
  11.         //get AEC data from the document
  12.          const aecdata = viewer.model.getDocumentNode().getAecModelData()
  13.         //get grids data
  14.          const grids = aecdata.grids
  15.  
  16.          const linesMaterial = new THREE.LineBasicMaterial({
  17.             color: 0xff0000,
  18.             linewidth: 2
  19.             })
  20.          const circleMaterial = new THREE.MeshBasicMaterial( { color: 0xffff00 } );
  21.        
  22.         //draw each grid one by one
  23.          grids.forEach(grid => {
  24.             //label
  25.             const lable = grid.label
  26.             const segments = grid.segments
  27.             //draw each segment one by one
  28.             segments.forEach(seg=>{
  29.                //start point
  30.                 const start = seg.points.start
  31.                 //end point
  32.                 const end = seg.points.end
  33.                
  34.                //grid line
  35.                 const lineGeo = new THREE.Geometry ()
  36.                 lineGeo.vertices.push (new THREE.Vector3 ( start[0],  start[1],  start[2]))
  37.                 lineGeo.vertices.push (new THREE.Vector3 ( end[0],  end[1],  end[2]))
  38.                 const line = new THREE.Line (lineGeo,linesMaterial) 
  39.                 NOP_VIEWER.impl.scene.add(line)
  40.  
  41.                 //grid circle
  42.                 var circleGeo = new THREE.CircleGeometry( 3, 32 );
  43.                 var circle = new THREE.Mesh( circleGeo, circleMaterial );
  44.                 viewer.impl.scene.add(circle)
  45.                 //transform the circle to the position of max point of bounding box of this grid.
  46.                 circle.position.set(grid.boundingBox[3]-1,grid.boundingBox[4],0 );
  47.  
  48.                 //get extension of drawing text
  49.                 let textExt= NOP_VIEWER.getExtension('Viewing.Extension.Text')
  50.                 //draw text
  51.                 textExt.createText({
  52.                     //intensionally to adjust the position of the text
  53.                     //will need to improve to make it more elegant
  54.                     position: {x: grid.boundingBox[3]-1, y: grid.boundingBox[4], z:  0},
  55.                     bevelEnabled: true,
  56.                     curveSegments: 24,
  57.                     bevelThickness: 0.1,
  58.                     color: 0x00ffff,
  59.                     text: grid.label,
  60.                     bevelSize: 0.1,
  61.                     height: 0.01,
  62.                     size: 2
  63.                     })
  64.           })
  65.         })
  66.          viewer.impl.sceneUpdated(true)
  67.      }

Результат выполнения метода показан на картинке в начале статьи

Источник: https://forge.autodesk.com/blog/consume-aec-data-which-are-model-derivative-api

Автор перевода: Александр Игнатович

Обсуждение: http://adn-cis.org/forum/index.php?topic=

Опубликовано 27.06.2019