Класс XYZ представляет координаты в RevitAPI. А раз мы имеем дело с координатами, то следует рассмотреть азы векторной геометрии. Всего два действия: сложение и вычитание векторов, позволят сделать кучу полезной работы.
Для начала предлагаю ознакомиться со спецификацией класса XYZ здесь. Что такое векторы можно почитать в википедии.
Класс XYZ в RevitAPI в пространстве модели можно представить в виде вектора, начало которого находится в нулевой точке или базовой точке проекта (X =0, Y = 0, Z = 0), а конец вектора находится в точке, которую нам указывают координаты, например XYZ (-44.6464513504241, 82.7973662674829, 33.0782338854701). Все значения координат указываются в футах. Класс XYZ имеет методы, присущие векторам, которые ниже будут рассмотрены.
Рассмотрим векторы на примере линии детализации в Ревит. Базовую точку отметим как А. Тогда первая точка линии (с которой мы начали ее вести) будет В, завершающая точка линии будет С. Соответственно мы получим векторы АВ и ВС.
В 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 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 + AF; AD = AB + BD;
По правилу параллелограмма, вместо векторов 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, www.bim3d.ru
* 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();
}
}
#region Revit Macros generated code
private void InternalStartup()
{
this.Startup += new System.EventHandler(Module_Startup);
this.Shutdown += new System.EventHandler(Module_Shutdown);
}
#endregion
}
}
Автор: Akunets