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

30/05/2018

Создание геометрии форм перехода (loft geometry) в Revit API

Сегодня мы немного поговорим о создании геометрических форм с использованием Revit API, а конкретнее о формах перехода (loft geometry), которые можно создать в редакторе семейств с помощью команд "Переход" и "Переход по траектории". Мы создадим геометрию путем перемещения выбранного профиля вдоль кривой, заданной функцией y=sin(x).

Для начала зададим профиль, лежащий в плоскости Y0Z. Метод создает CurveLoop, формирующий наш профиль с возможностью его масштабирования:

Код - C#: [Выделить]
  1.  
  2. private static CurveLoop CreateProfile(double scale)
  3. {
  4.                 var a = new XYZ(0, -1, -1);
  5.                 var b = new XYZ(0, 1, -1);
  6.                 var c = new XYZ(0, 1, 0);
  7.                 var d = new XYZ(0, 0, 1);
  8.                 var e = new XYZ(0, -1, 1);
  9.  
  10.                 var curvesList = new List<Curve>
  11.                                {
  12.                                                Line.CreateBound(scale*a, scale*b),
  13.                                                Line.CreateBound(scale*b, scale*c),
  14.                                                Line.CreateBound(scale*c, scale*d),
  15.                                                Line.CreateBound(scale*d, scale*e),
  16.                                                Line.CreateBound(scale*e, scale*a)
  17.                                };
  18.  
  19.                 return CurveLoop.Create(curvesList);
  20. }
  21.  

Наш профиль выглядит вот так:

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

На рисунке зеленым показана плоскость профиля, красным - её нормаль. Для решения задачи, на проще всего будет работать с аффинными преобразованиями, которые в Revit API инкапсулирует класс Transform. Требуемое нам преобразование T будет представлять собой произведение T=Tm*Tr, где Tm - перемещение в заданную точку, а Tr  - поворот на заданный угол.

Пусть наша синусоида располагается в плоскости X0Y. Зададим функцию, возвращающую требуемый нам T для заданного X. Очевидно, что перемещение в нужную нам точку Tm будет переносом в точку (x, sin(x), 0). С поворотом немного сложнее. Фактически, нам нужно знать направление нормали профиля, которое совпадает с направлением движения по траектории, а направление движения по траектории задается производной функции. Тогда искомый угол a=cos(x). Итого метод для получения нужного нам преобразования будет выглядеть следующим образом:

Код - C#: [Выделить]
  1.  
  2. private static Transform CreateSinusTransform(double point)
  3. {
  4.                 var translation = Transform.CreateTranslation(new XYZ(point, Math.Sin(point), 0));
  5.  
  6.                 var rotation = Transform.CreateRotation(XYZ.BasisZ, Math.Cos(point));
  7.  
  8.                 return translation*rotation;
  9. }
  10.  

 

Тогда мы сможем получить перечень профилей следующим образом:

Код - C#: [Выделить]
  1.  
  2. const double scale = 0.2;
  3. const double length = 4.0*Math.PI;
  4. const int steps = 16;
  5.  
  6. var profile = CreateProfile(scale);
  7.  
  8. var profiles = Enumerable
  9.                 .Range(0, steps + 1)
  10.                 .Select(x => x*length/steps)
  11.                 .Select(CreateSinusTransform)
  12.                 .Select(x => profile.CreateTransformed(x))
  13.                 .ToList();
  14.  

Здесь CreateTransformed - это Extension-метод, его реализация достаточно тривиальна:

Код - C#: [Выделить]
  1.  
  2. public static class CurveLoopExtensions
  3. {
  4.                 public static CurveLoop CreateTransformed(this CurveLoop curveLoop, Transform transform)
  5.                 {
  6.                                var curves = curveLoop
  7.                                                .Select(x => x.CreateTransformed(transform))
  8.                                                .ToList();
  9.  
  10.                                return CurveLoop.Create(curves);
  11.                 }
  12. }
  13.  

В 3D это будет выглядеть следующим образом (где красным опять же показана нормаль профиля):

Теперь, имея перечень профилей, мы можем создать нужную нам геометрию (Solid):

Код - C#: [Выделить]
  1.  
  2. var solid = GeometryCreationUtilities.CreateLoftGeometry(profiles,
  3.                 new SolidOptions(ElementId.InvalidElementId, ElementId.InvalidElementId));
  4.  

При работе в редакторе семейств, можно создать FreeFormElement, но я делаю это в проекте, а для создания произвольной геометрии в проекте предназначены механизмы DirectShape:

Код - C#: [Выделить]
  1.  
  2. var directShape = DirectShape.CreateElement(doc, new ElementId(BuiltInCategory.OST_GenericModel));
  3.  
  4. directShape.AppendShape(new GeometryObject[] {solid});
  5.  

Результат работы:

 

Полный код доступен по ссылке: https://github.com/CADBIMDeveloper/Just-for-fun/tree/master/src/CreateLoftWithSinusProfile

 

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

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

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