27 подписчиков

Векторная геометрия для разработчиков Revit API

238 прочитали

Класс XYZ представляет координаты в RevitAPI. А раз мы имеем дело с координатами, то следует рассмотреть азы векторной геометрии. Всего два действия: сложение и вычитание векторов, позволят сделать кучу полезной работы.

Для начала предлагаю ознакомиться со спецификацией класса XYZ здесь . Что такое векторы можно почитать в википедии .

Класс XYZ в RevitAPI в пространстве модели можно представить в виде вектора, начало которого находится в нулевой точке или базовой точке проекта (X =0, Y = 0, Z = 0), а конец вектора находится в точке, которую нам указывают координаты, например XYZ (-44.6464513504241, 82.7973662674829, 33.0782338854701). Все значения координат указываются в футах. Класс XYZ имеет методы, присущие векторам, которые ниже будут рассмотрены.

Рассмотрим векторы на примере линии детализации в Ревит. Базовую точку отметим как А. Тогда первая точка линии (с которой мы начали ее вести) будет В, завершающая точка линии будет С. Соответственно мы получим векторы АВ и ВС.

Класс XYZ представляет координаты в RevitAPI. А раз мы имеем дело с координатами, то следует рассмотреть азы векторной геометрии.

В Revit API предусмотрены методы для доступа к первой точке и последней точки линии.

Reference r =  uiapp.ActiveUIDocument.Selection.PickObject(ObjectType.Element)
Element line = doc.GetElement(r.ElementId);
XYZ vectorAB = (line.Location as LocationCurve).Curve.GetEndPoint(0);
XYZ vectorAC = (line.Location as LocationCurve).Curve.GetEndPoint(1);
TaskDialog.Show("Векторы", vectorAB.ToString() + "\n" + vectorAC);

Для работы с линией детализации как с вектором нам нужен вектор ВС. Для получения вектора линии детализации ВС используем вычитание векторов.

ВС = АС - АВ

Класс XYZ представляет координаты в RevitAPI. А раз мы имеем дело с координатами, то следует рассмотреть азы векторной геометрии.-2

Все просто, в данном выражении конец вектора АС будет будет концом вектора ВС  (первое число в разности - конец). Конец вектора АВ будет началом вектора ВС (второе число в разности - начало).

XYZ vectorBC = vectorAC - vectorAB;

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

XYZ vectorBC_1 = vectorBC * (-2) // удлиняется в сторону точки B
XYZ vectorBC_2 = vectorBC * 2; // удлиняется в сторону точки С
XYZ vectorBC_05 = vectorBC * .5 // середина вектора ВС
// код создания линии
Line line = Line.CreateBound(vectorAB, vectorBC_2); // начальная и конечная точка, ведь класс XYZ - это координаты
doc.Create.NewDetailCurve(doc.ActiveView, line);

Далее рассмотрим сложение векторов.

Сложение векторов очень пригодится, если нужно разместить какой-либо объект на определенном расстоянии от уже известной точки. Для этого нужно будет воспользоваться координатами такой точки и нормализованным вектором (или единичным вектором). Нормализованный или единичный вектор - это вектор, длина которого равна единице. Подробнее читайте тут .

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

AF = AC + СF; AD = AB + BD;

Класс XYZ представляет координаты в RevitAPI. А раз мы имеем дело с координатами, то следует рассмотреть азы векторной геометрии.-3

По правилу параллелограмма, вместо векторов CF и BD мы можем воспользоваться вектором AX, который очень просто вычисляется. Воспользуемся нормализованным вектором, который в наше распоряжение предоставляет Revit API - это XYZ.BasisX. Длина этого вектора равна единице, и он, как все базисные векторы, расположен в начале координат. Поэтому умножим его на 2000мм, не забывая перевести миллиметры в футы.

XYZ vectorAX = XYZ.BasisX * (2000 / 304.8);
// Находим веторы AF и AD
XYZ vectorAF = vectorAC + vectorAX;
XYZ vectorAD = vectorAB +  vectorAX;

Найденные векторы vectorAF и vectorAD являются точными координатами для построения новой линии детализации.

Посмотрим как можно, например удлинить нашу линию детализации на 1000 мм в сторону точки С или B.

// Удлиняем в сторону точки С
XYZ directionToC = vectorBC.Normalize();
XYZ newC = vectorAC + (directionToC * (1000 / 304.8));
// Удлиняем в с сторону точки В
XYZ vectorCB = vectorAB - vectorAC;
XYZ directionToB = vectorCB.Normalize();
XYZ newB = vectorAB + (directionToB * (1000 / 304.8));

Пару слов о методе Normalize класса XYZ. Normalize возвращает нормализованный вектор BC или CB. То есть это вектор BC или CB, укороченный до длины равной 1 и помещенный в начало координат с сохранением направления.

Для увлекательного путешествия по трехмерному миру при разработке программ для Ревит нам нужна только опорная точка с известными координатами и указатель движения в виде нормализованного (единичного) вектора, и расстояние. Произведение указателя с расстоянием, и прибавленная к ним опорная точка дадут новые координаты. Пространство проекта в Ревит просто наполнено указателями, которые можно  получать из многих элементов. Мы можем вычислять свои указатели как в примере выше.

Для комфортного путешествия по трехмерному миру нам нужно еще вооружиться знаниями о нормали к прямой или к поверхности и скалярным произведением векторов . Нужно получить информацию о пересечении прямых и, популярным в Ревит, частным случаем - пересечении отрезков.

Ниже можно посмотреть листинг макроса для Ревит, который сдвигает выбранную линию детализации на 2000мм вправо и удлиняет ее на 1000мм в обе стороны.

/*
;* Created by SharpDevelop.
 * User: Akunets Aleksandr
 * Date: 27.08.2017
 * Time: 20:37
 * 
 * To change this template use Tools | Options | Coding | Edit Standard Headers.
 */
using System;
using Autodesk.Revit.UI;
using Autodesk.Revit.DB;
using Autodesk.Revit.UI.Selection;
using System.Collections.Generic;
using System.Linq;

namespace Vector
{
    [Autodesk.Revit.Attributes.Transaction(Autodesk.Revit.Attributes.TransactionMode.Manual)]
    [Autodesk.Revit.DB.Macros.AddInId("17333FA7-9C10-4B4E-A179-7B56E33FC6B3")]
    public partial class ThisApplication
    {
        private void Module_Startup(object sender, EventArgs e)
        {

        }

        private void Module_Shutdown(object sender, EventArgs e)
        {

        }

        public void Vector() {

            UIDocument uidoc = this.ActiveUIDocument; 

            Document doc = uidoc.Document; //получаем документ

            Selection selection = uidoc.Selection; 

            Reference r    = selection.PickObject(ObjectType.Element, "Выделите линию детализации"); // получаем линию

            Element line = doc.GetElement(r.ElementId); // получаем линию как элемент

            XYZ vectorAB = (line.Location as LocationCurve).Curve.GetEndPoint(0); // получаем вектор к первой точке

             XYZ vectorAC = (line.Location as LocationCurve).Curve.GetEndPoint(1); // получаем вектор ко второй точке

             XYZ vectorBC = vectorAC - vectorAB; // получаем вектор, определяющий линию детализации

             XYZ vectorAX = XYZ.BasisX * (2000 / 304.8); // получаем вектор сдвига на 2000мм вправо (от нулевой точки 2000мм вправо)

             XYZ vectorAF = vectorAC + vectorAX; // получаем вектор (координаты) новой точки

            XYZ vectorAD = vectorAB +  vectorAX; // получаем вектор (координаты) новой точки

            XYZ directionToC = vectorBC.Normalize(); // получаем направление (единичный вектор) в сторону точки С,
            // и используем его для любых параллельных ему векторов

            XYZ newC = vectorAF + (directionToC * (1000 / 304.8)); // получаем вектор (координаты) новой точки для новой линии

            // Удлиняем в с сторону точки В
            XYZ vectorCB = vectorAB - vectorAC; // получаем вектор, зеркальный вектору BC

            XYZ directionToB = vectorCB.Normalize(); // получаем направление (единичный вектор) в сторону точки B,
            // и используем его для любых параллельных ему векторов

            XYZ newB = vectorAD + (directionToB * (1000 / 304.8)); // получаем вектор (координаты) новой точки для новой линии
Transaction t = new Transaction(doc, "Create Detail Line");
            {
                t.Start();

                Line geomLine = Line.CreateBound(newB, newC);

                DetailLine detailline = doc.Create.NewDetailCurve(doc.ActiveView, geomLine ) as DetailLine;

                t.Commit();
            }
        }
        private void InternalStartup()
        {
            this.Startup += new System.EventHandler(Module_Startup);
            this.Shutdown += new System.EventHandler(Module_Shutdown);
        }     
    }
}

PS: Ознакомится с азами векторной алгебры вы можете в этой статье - Линейная алгебра для разработчиков игр