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

22/07/2013

Создание перекрытия (пола) с несколькими границами или проемами

Вопрос: Мне нужно программно создать перекрытие (пол). Проблема возникает тогда, когда перекрытие имеет несколько границ (например, внешняя и внутренняя границы), как изображено на рисунке

Revit API дает нам только один метод для создания перекрытия – Document.NewFloor. В качестве одного из параметров необходимо передать CurveArray (массив кривых), которые должны быть замкнуты. Новое перекрытие будет создано по этим кривым.

Но, используя этот метод, я не могу создать сложное перекрытие как на скриншоте выше. Если я создаю массив линий и добавляю туда 8 линий (4 на внешнюю границу и 4 на внутреннюю), в итоге создается вот такое перекрытие:

Также я не могу найти какой-либо другой способ как получить существующие границы пола, кроме как использую API для работы с геометрией.

Так есть ли способ создать пол, если несколькими границами?

Ответ: Вот несколько примеров использования метода NewFloor которые я когда-то упоминал:

Со всеми ли вы ознакомились?

В блоге обсуждаются как сделать отверстие в перекрытие создав проем.

Есть ли другой способ создания перекрытия с отверстием с помощью пользовательского интерфейса, или также требуется создать сначала перекрытие, а затем проем? Если это возможно, то можно надеяться что API также позволяет это сделать.

Чаще всего API не позволяет сделать больше, чем возможно сделать с помощью пользовательского интерфейса.

Отклик на ответ: На самом деле я уже научился копировать пол без проема как в вашем примере edit a floor profile. После прочтения статей, о которых вы упомянули, я создал метод для копирования уже существующего перекрытия с проемами. Сначала я предположил, что первый элемент EdgeArray, возвращаемый свойством Face.EdgeLoops, является внешней границей перекрытия, а все последующие – границами проемов. Как оказалось, это не всегда так.

Ниже представлен код первой попытки реализации копирования:

Код - C#: [Выделить]
  1.  
  2. private Floor CopyFloor(Floor sourceFloor)
  3.         {
  4.             var floorGeometryElement =
  5.                 sourceFloor.get_Geometry(new Options());
  6.  
  7.             foreach (var geometryObject in floorGeometryElement)
  8.             {
  9.                 var floorSolid =
  10.                     geometryObject as Solid;
  11.  
  12.                 if (floorSolid == null)
  13.                     continue;
  14.  
  15.                 var topFace =
  16.                     GetTopFace(floorSolid);
  17.  
  18.                 if (topFace == null)
  19.                     throw new NotSupportedException("Floor does not have top face");
  20.  
  21.                 if (topFace.EdgeLoops.IsEmpty)
  22.                     throw new NotSupportedException("Floor top face does not have edges");
  23.  
  24.                 var outerBoundary =
  25.                     topFace.EdgeLoops.get_Item(0);
  26.  
  27.                 // create new floor using source floor outer boundaries
  28.  
  29.                 CurveArray floorCurveArray =
  30.                     GetCurveArrayFromEdgeArary(outerBoundary);
  31.               
  32.                 var newFloor =
  33.                     sourceFloor
  34.                         .Document
  35.                         .Create
  36.                         .NewFloor(floorCurveArray, false);
  37.  
  38.                
  39.                 // if source floor has openings
  40.                 if (topFace.EdgeLoops.Size > 1)
  41.                 {
  42.                     for (int i = 1; i < topFace.EdgeLoops.Size; i++)
  43.                     {
  44.                         var openingEdges =
  45.                             topFace.EdgeLoops.get_Item(i);
  46.  
  47.                         var openingCurveArray =
  48.                             GetCurveArrayFromEdgeArary(openingEdges);
  49.  
  50.                         var opening =
  51.                             sourceFloor
  52.                                 .Document
  53.                                 .Create
  54.                                 .NewOpening(newFloor,
  55.                                             openingCurveArray,
  56.                                             true);
  57.                     }
  58.                 }
  59.                
  60.                 return newFloor;
  61.             }
  62.  
  63.             return null;
  64.         }
  65.  
  66.         private CurveArray GetCurveArrayFromEdgeArary(EdgeArray edgeArray)
  67.         {
  68.             CurveArray curveArray =
  69.                 new CurveArray();
  70.  
  71.             foreach (Edge edge in edgeArray)
  72.             {
  73.                 var edgeCurve =
  74.                         edge.AsCurve();
  75.  
  76.                 curveArray.Append(edgeCurve);
  77.             }
  78.  
  79.             return curveArray;
  80.         }
  81.  
  82.  
  83.         PlanarFace GetTopFace(Solid solid)
  84.         {
  85.             PlanarFace topFace = null;
  86.             FaceArray faces = solid.Faces;
  87.             foreach (Face f in faces)
  88.             {
  89.                 PlanarFace pf = f as PlanarFace;
  90.                 if (null != pf
  91.                   && (Math.Abs(pf.Normal.X - 0) < _eps && Math.Abs(pf.Normal.Y - 0) < _eps))
  92.                 {
  93.                     if ((null == topFace)
  94.                       || (topFace.Origin.Z < pf.Origin.Z))
  95.                     {
  96.                         topFace = pf;
  97.                     }
  98.                 }
  99.             }
  100.             return topFace;
  101.         }
  102.  

Но, когда я попытался его выполнить, я получил  ошибку:

 

Причина была в том, что Revit не может создать проем в перекрытии до тех пор, пока не будет подтверждена транзакция, в которой перекрытие было создано. То есть нужно сначала создать перекрытие, а уже затем проем. В одной транзакции это сделать нельзя.

В своей второй попытке, я сначала копирую перекрытие без проема, фиксирую транзакцию, а уже после этого создаю проемы.

Такой метод работает. Полный код команды для копирования пола.

Результат

 

Снизу находится перекрытие, созданное в интерфейсе Revit, а сверху – перекрытие, созданное программно.

Но, как вы заметили, скопированное перекрытие не является точной копией оригинала. 

 

Они лишь похожи визуально

 

Исходное перекрытие не имеет проема. Оригинальное перекрытие имеет сложные границы (внутренняя и внешняя).

Также проблема в том, что мой подход с определением проемов не очень верен.  Первый элемент возвращаемый свойством Face.EdgeLoops не всегда является внешней границей. Перекрытие может иметь несколько EdgeArrays при этом не иметь проемов. Пример такого перекрытия представлен на скриншоте:

 

Это один элемент Перекрытие. Геометрия элемента содержит только одну фигуру. Верхняя поверхность этой фигуры имеет 4 границы EdgeArrays и при этом не содержит проемов. Таким образом нужно научиться определять, является ли EdgeArray границей отверстия или нет. Я думаю это можно сделать проверяя находится ли каждая граница массива EdgeArray внутри предыдущего массива и если это действительно так, значит EdgeArray является границей проема.

Другая проблема: даже если я определю все проемы и создам копию исходного перекрытия, то я не смогу создать копию копии с помощью этого же метода.

 

Небольшое заключение

  • Нет способа создать точную копию перекрытия с отверстиями используя API
  • Существует способ создать отверстия в перекрытии с помощью проемов.

Исходный код проекта можно скачать по ссылке или на GitHub.

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

Опубликовано 22.07.2013
Отредактировано 23.07.2013 в 08:50:23