Создание перекрытия (пола) с несколькими границами или проемами
Вопрос: Мне нужно программно создать перекрытие (пол). Проблема возникает тогда, когда перекрытие имеет несколько границ (например, внешняя и внутренняя границы), как изображено на рисунке
Revit API дает нам только один метод для создания перекрытия – Document.NewFloor. В качестве одного из параметров необходимо передать CurveArray (массив кривых), которые должны быть замкнуты. Новое перекрытие будет создано по этим кривым.
Но, используя этот метод, я не могу создать сложное перекрытие как на скриншоте выше. Если я создаю массив линий и добавляю туда 8 линий (4 на внешнюю границу и 4 на внутреннюю), в итоге создается вот такое перекрытие:
Также я не могу найти какой-либо другой способ как получить существующие границы пола, кроме как использую API для работы с геометрией.
Так есть ли способ создать пол, если несколькими границами?
Ответ: Вот несколько примеров использования метода NewFloor которые я когда-то упоминал:
- Примеры из SDK: FoundationSlab, GenerateFloor
- RevitLookup: Utils/Elements.cs и TestElements.cs
- Статьи блога:
- Editing a Floor Profile (на англ.)
- Boolean Operations for 2D Polygons (на англ.)
- Hole in a Floor (на англ.)
- Floor Creation (на англ.)
- Pick Corners and Create Floor (на англ.)
- Validate Roof Type and View OBJ on Android (на англ.)
Со всеми ли вы ознакомились?
В блоге обсуждаются как сделать отверстие в перекрытие создав проем.
Есть ли другой способ создания перекрытия с отверстием с помощью пользовательского интерфейса, или также требуется создать сначала перекрытие, а затем проем? Если это возможно, то можно надеяться что API также позволяет это сделать.
Чаще всего API не позволяет сделать больше, чем возможно сделать с помощью пользовательского интерфейса.
Отклик на ответ: На самом деле я уже научился копировать пол без проема как в вашем примере edit a floor profile. После прочтения статей, о которых вы упомянули, я создал метод для копирования уже существующего перекрытия с проемами. Сначала я предположил, что первый элемент EdgeArray, возвращаемый свойством Face.EdgeLoops, является внешней границей перекрытия, а все последующие – границами проемов. Как оказалось, это не всегда так.
Ниже представлен код первой попытки реализации копирования:
- private Floor CopyFloor(Floor sourceFloor)
- {
- var floorGeometryElement =
- sourceFloor.get_Geometry(new Options());
- foreach (var geometryObject in floorGeometryElement)
- {
- var floorSolid =
- geometryObject as Solid;
- if (floorSolid == null)
- continue;
- var topFace =
- GetTopFace(floorSolid);
- if (topFace == null)
- throw new NotSupportedException("Floor does not have top face");
- if (topFace.EdgeLoops.IsEmpty)
- throw new NotSupportedException("Floor top face does not have edges");
- var outerBoundary =
- topFace.EdgeLoops.get_Item(0);
- // create new floor using source floor outer boundaries
- CurveArray floorCurveArray =
- GetCurveArrayFromEdgeArary(outerBoundary);
- var newFloor =
- sourceFloor
- .Document
- .Create
- .NewFloor(floorCurveArray, false);
- // if source floor has openings
- if (topFace.EdgeLoops.Size > 1)
- {
- for (int i = 1; i < topFace.EdgeLoops.Size; i++)
- {
- var openingEdges =
- topFace.EdgeLoops.get_Item(i);
- var openingCurveArray =
- GetCurveArrayFromEdgeArary(openingEdges);
- var opening =
- sourceFloor
- .Document
- .Create
- .NewOpening(newFloor,
- openingCurveArray,
- true);
- }
- }
- return newFloor;
- }
- return null;
- }
- private CurveArray GetCurveArrayFromEdgeArary(EdgeArray edgeArray)
- {
- CurveArray curveArray =
- new CurveArray();
- foreach (Edge edge in edgeArray)
- {
- var edgeCurve =
- edge.AsCurve();
- curveArray.Append(edgeCurve);
- }
- return curveArray;
- }
- PlanarFace GetTopFace(Solid solid)
- {
- PlanarFace topFace = null;
- FaceArray faces = solid.Faces;
- foreach (Face f in faces)
- {
- PlanarFace pf = f as PlanarFace;
- if (null != pf
- && (Math.Abs(pf.Normal.X - 0) < _eps && Math.Abs(pf.Normal.Y - 0) < _eps))
- {
- if ((null == topFace)
- || (topFace.Origin.Z < pf.Origin.Z))
- {
- topFace = pf;
- }
- }
- }
- return topFace;
- }
Но, когда я попытался его выполнить, я получил ошибку:
Причина была в том, что Revit не может создать проем в перекрытии до тех пор, пока не будет подтверждена транзакция, в которой перекрытие было создано. То есть нужно сначала создать перекрытие, а уже затем проем. В одной транзакции это сделать нельзя.
В своей второй попытке, я сначала копирую перекрытие без проема, фиксирую транзакцию, а уже после этого создаю проемы.
Такой метод работает. Полный код команды для копирования пола.
Результат
Снизу находится перекрытие, созданное в интерфейсе Revit, а сверху – перекрытие, созданное программно.
Но, как вы заметили, скопированное перекрытие не является точной копией оригинала.
Они лишь похожи визуально
Исходное перекрытие не имеет проема. Оригинальное перекрытие имеет сложные границы (внутренняя и внешняя).
Также проблема в том, что мой подход с определением проемов не очень верен. Первый элемент возвращаемый свойством Face.EdgeLoops не всегда является внешней границей. Перекрытие может иметь несколько EdgeArrays при этом не иметь проемов. Пример такого перекрытия представлен на скриншоте:
Это один элемент Перекрытие. Геометрия элемента содержит только одну фигуру. Верхняя поверхность этой фигуры имеет 4 границы EdgeArrays и при этом не содержит проемов. Таким образом нужно научиться определять, является ли EdgeArray границей отверстия или нет. Я думаю это можно сделать проверяя находится ли каждая граница массива EdgeArray внутри предыдущего массива и если это действительно так, значит EdgeArray является границей проема.
Другая проблема: даже если я определю все проемы и создам копию исходного перекрытия, то я не смогу создать копию копии с помощью этого же метода.
Небольшое заключение
- Нет способа создать точную копию перекрытия с отверстиями используя API
- Существует способ создать отверстия в перекрытии с помощью проемов.
Исходный код проекта можно скачать по ссылке или на GitHub.
Обсуждение: http://adn-cis.org/forum/index.php?topic=120.0
Отредактировано 23.07.2013 в 08:50:23