Определение типа поверхности под выбранной точкой
Вопрос: Я пишу надстройку для Revit 2015 где мне нужно вставить семейство в проект.
Я хочу вставить семейство сразу на поверхность существующего элемента. Но, в зависимости от ситуации, я должен его вставить на различный тип поверхности. Например, на плоскую поверхность или цилиндрическую. Проблема в том, что я не могу определить тип поверхности перед тем как делать вставку.
Вот мой код для цилиндрической поверхности:
- Reference r = uidoc.Selection.PickObject(
- ObjectType.Face, "Выберите точку на поверхности "
- + "для вставки семейства." );
- Element e = doc.GetElement( r.ElementId );
- GeometryObject obj
- = e.GetGeometryObjectFromReference( r );
- //PlanarFace face = obj as PlanarFace;
- CylindricalFace face = obj as CylindricalFace;
- XYZ p = r.GlobalPoint;
- XYZ v = face.Axis.CrossProduct( XYZ.BasisZ );
- if( v.IsZeroLength() )
- {
- v = face.Axis.CrossProduct( XYZ.BasisX );
- }
- doc.Create.NewFamilyInstance( r, p, v, symbol );
И для плоской поверхности:
- Reference r = uidoc.Selection.PickObject(
- ObjectType.Face, " Выберите точку на поверхности "
- + "для вставки семейства.");
- Element e = doc.GetElement( r.ElementId );
- GeometryObject obj
- = e.GetGeometryObjectFromReference( r );
- PlanarFace face = obj as PlanarFace;
- //CylindricalFace face = obj as CylindricalFace;
- XYZ p = r.GlobalPoint;
- XYZ v = face.Normal.CrossProduct( XYZ.BasisZ );
- if( v.IsZeroLength() )
- {
- v = face.Normal.CrossProduct( XYZ.BasisX );
- }
- doc.Create.NewFamilyInstance( r, p, v, symbol );
Почти ничего не меняется, за исключением определения вектора v.
У меня есть еще и другие вопросы:
Сейчас я ввел путь и имя файла семейства прямо в коде. В идеале, я бы хотел, чтобы пользователь выбирал семейство, когда он запускает надстройку. Но у меня абсолютно нет идей как это сделать.
После того, как семейство вставлено, как можно автоматически запустить проверку на пересечения и посмотреть, нет ли коллизий. Плагин нацелен на людей, которые ни разу не работали с приложениями, типа AutoCAD и я хочу, чтоб было как можно меньше кнопок, которые им нужно нажимать.
Ответ: Спасибо за вопросы.
Идея проекта выглядит неплохо.
Проверка типа поверхности
Вы можете проеверить тип поверхности довольно легко. Например, вот так:
- if( obj is PlanarFace )
- {
- PlanarFace planarFace = obj as PlanarFace;
- // обрабатываем плоскую поверхность
- }
- else if( obj is CylindricalFace )
- {
- CylindricalFace cylindricalFace = obj
- as CylindricalFace;
- // и цилиндрическую.
- }
Хотя было бы лучше не разделять цилиндрическую и плоскую грани поверхности. Все что вам нужно – это вектор v, верно? И вы хотите, чтобы он относился к выбранной поверхности?
Тогда этого можно добиться более обобщенным способом, без привязки к типу поверхности.
Определение общей касательной поверхности
Заданная в Revit API геометрическая рань – это наиболее легкий способ определить касательный вектор на заданной точке. Это можно сделать с помощью метода Face.ComputeDerivatives.
Единственное что требуется для использования данного метода, это координаты UV, лежащие на поверхности грани в координатной системе этой грани. Точка XYZ в трехмерном пространстве определяется с помощью метода PickObject. Можно воспользоваться методом Face.Project, чтобы определить нужную точку на грани.
Таким образом, ComputeDerivatives можно использовать для определения касательной поверхности вне зависимости от ее типа:
- /// <summary>
- /// Помещает экземпляр семейства на выбранную поверхность
- /// существующего элемента
- /// </summary>
- FamilyInstance PlaceFamilyInstanceOnFace(
- UIDocument uidoc,
- FamilySymbol symbol )
- {
- Document doc = uidoc.Document;
- Reference r = uidoc.Selection.PickObject(
- ObjectType.Face, " Выберите точку на поверхности "
- + "для вставки семейства.");
- Element e = doc.GetElement( r.ElementId );
- GeometryObject obj
- = e.GetGeometryObjectFromReference( r );
- XYZ p = r.GlobalPoint;
- // Не зацикливаясь на конкретных типах поверхностей,
- // будем использовать общий метод
- Face face = obj as Face;
- IntersectionResult ir = face.Project( p );
- UV q = ir.UVPoint;
- Transform t = face.ComputeDerivatives( q );
- XYZ v = t.BasisX; // or BasisY, or whatever...
- return doc.Create.NewFamilyInstance(r, p, v, symbol);
- }
Как вы видите, метод выглядит довольно красиво и не нужно заботиться о том, с каким типом поверхности вы имеете дело.
Непосредственное использование UV точки
Рассмотрим еще один вариант. Я уже отмечал, что метод объект Referencе, возвращаемый методом PickPoint, предоставляет доступ к точке UV на поверхности, поэтому уже не нужно делать проекцию 3D точки на поверхность. Код становится гораздо проще:
- Reference r = uidoc.Selection.PickObject(
- ObjectType.Face, "Выберите точку на поверхности "
- + " для вставки семейства" );
- Element e = doc.GetElement( r.ElementId );
- GeometryObject obj
- = e.GetGeometryObjectFromReference( r );
- Face face = obj as Face;
- UV q = r.UVPoint;
- Transform t = face.ComputeDerivatives( q );
- XYZ v = t.BasisX; // or BasisY, or whatever...
- return doc.Create.NewFamilyInstance( r, p, v, symbol );
Путь к файлу семейства
Для того чтобы пользователь могу выбрать путь и название семейство для вставки, можно использовать стандартным классом .NET OpenFileDialog для выбора файла семейства rfa. После того, как файл выбран, можно его загружать с помощью метода LoadFamily.
Проверка на пересечения и коллизии
Проверка на пересечения является более сложной задачей. И здесь возможны различные варианты осуществления поставленной задачи. Первое что приходит в голову:
- Определить твердотельный объект вставленного семейства (solid)
- Создать фильтр ElementIntersectsSolidFilter, используя этот объект.
- Получить все элементы, извлеченные с помощью фильтра.
В примерах The Building Coder есть команда CmdCollectorPerformance, в котором вызывается метод GetInstancesIntersectingElement для демонстрации использования фильтра ElementIntersectsSolidFilter.
Также на сайте The Building Coder есть множество тем, связанных с определением пересечений и поиска коллизий (на англ.)
Источник: http://thebuildingcoder.typepad.com/blog/2015/02/determining-the-face-tangent-at-a-picked-point.html
Обсуждение: http://adn-cis.org/forum/index.php?topic=1915
Опубликовано 08.03.2015Отредактировано 08.03.2015 в 16:47:47