Как определить месторасположение элемента из связанного файла в системе координат основного файла
Вопрос: Я все воюю со связанными файлами в Revit 2014.
Я прочитал статью Как вывести список элементов из связанного файла (на англ.) и она мне действительно очень помогла.
Проблема в том, что в той статье описывается как получить координаты элемента в системе координат связанного файла.
Скажем, есть у меня связанный файл, в котором находится только одна стена. В этом файле стена располагается в точке 100;100;0.
В основном файле, я поместил эту стену в точку 300;100;0.
Мне нужно определить расположение стены из связанного файла внутри основного файла. То есть я хочу получить координаты 300;100;0.
Как можно это сделать?
Как я уже сказал, код из вышеупомянутой статьи определяет месторасположение стены в координатах связанного файла (100;100;0), а это совсем не те координаты, которые мне нужны.
- Document d = rvtlink.GetLinkDocument();
- Element e = d.GetElement( id );
- LocationCurve curve = e.Location as LocationCurve;
- XYZ p = curve.Curve.GetEndPoint( 0 );
- XYZ q = curve.Curve.GetEndPoint( 1 );
Чтобы полностью описать и воспроизвести мою проблему, я создал два тестовых проекта, А и В, и две стены – синюю и красную.
Проект А выглядит вот так:
Красная стена располагается в нулевой точке (0;0;0) этого проекта. Синяя в точке -12000;0;0
Проект В выглядит так:
Розовая линия обозначает границу связанного файла проекта А в проекте В.
Проект А располагается в проекте В таким образом, что нулевая точка проекта А находится в точке 5000;5000;0 проекта В.
Как говорил, моя цель – получить координаты расположения красной стены (стены из связанного файла), но в системе координат проекта В.
Таким образом, мне нужен некий алгоритм, с помощью которого я могу определить, что красная стена находится в точке 5000;5000;0, а синяя – в точке -7000;5000;0.
Так как можно это сделать?
Вот мой код, где я пытался получить то, что мне нужно:
- UIApplication uiapp = commandData.Application;
- UIDocument uidoc = uiapp.ActiveUIDocument;
- Document doc = uidoc.Document;
- Selection sel = uidoc.Selection;
- Reference r = sel.PickObject(
- ObjectType.Element,
- new LinkSelectionFilter(),
- "Выбериете связанный файл" );
- RevitLinkInstance rvtlink = doc.GetElement( r )
- as RevitLinkInstance;
- if( rvtlink == null )
- {
- return Result.Failed;
- }
- // В примере рассмотрим только
- // синюю и красную стены
- var walls = new FilteredElementCollector(
- rvtlink.GetLinkDocument() )
- .OfClass( typeof( Wall ) )
- .Where( c => c.Id.IntegerValue == 179910
- || c.Id.IntegerValue == 179980 );
- foreach( Wall wall in walls )
- {
- // Определим координаты; Но эти координаты
- // относятся к связанному файла, т.е. к проекту А.
- LocationCurve curve = wall.Location
- as LocationCurve;
- XYZ p = curve.Curve.GetEndPoint( 0 );
- XYZ q = curve.Curve.GetEndPoint( 1 );
- if( wall.Id.IntegerValue == 179910 )
- {
- TaskDialog.Show( "Красная стена",
- "Красная стена располагается в точке "
- + PointString( p ) );
- }
- else
- {
- TaskDialog.Show( "Синяя стена",
- "Синяя стена располагается в точке: "
- + PointString( p ) );
- }
- // Так как определить координаты
- // синей и красной стен в системе координат
- // проекта В?
- }
- return Result.Succeeded;
Как мне реализовать последний шаг?
Ответ: На самом деле, очень легко.
Перед тем как углубиться в детали, я хотел бы заметить, что я недавно обсуждал как получить доступ к отдельным элементам из связанного файла (на англ.) и там я указывал достаточно большое количеств ссылок на подобные темы.
Класс RevitLinkInstance наследуется от класса Instance. Класс содержит метод GetTransform, с помощью которого можно получить данные о преобразовании элемента, а также метод GetTotalTransform, который возвращает текущее преобразование элемента с направлением на север.
Как вы сказали, у вас есть координаты элемента в связанном файле, а нужно определить, как преобразовать эти координаты в систему координат основного файла.
Этого легко достичь, используя свойство Location класса RevitLinkInstance, чтобы определить смещение координаты связанного файла относительно основного, а затем применить это смещение к координатам, которые вы уже смогли получить.
Кстати, я хотел бы заметить, что вы значительно усложняете отладку кода, работая с миллиметрами в пользовательском интерфейсе, так как все значения внутри базы данных файла Revit хранятся в футах.
Я реализовал небольшой вспомогательный метод PointStringMm для отображения единиц измерения базы данных в миллиметрах.
- const double _inch_to_mm = 25.4;
- const double _foot_to_mm = 12 * _inch_to_mm;
- /// <summary>
- /// Возвращает строку для числа с плавающей точкой
- /// отформатированную до двух знаков после запятой
- /// </summary>
- public static string RealString( double a )
- {
- return a.ToString( "0.##" );
- }
- /// <summary>
- /// Возвращает строку для трехмерной точки XYZ
- /// или вектора с координатами этой точки
- /// преобразованную из футов в миллиметры
- /// и отформатированную до двух знаков после запятой
- /// </summary>
- public static string PointStringMm( XYZ p )
- {
- return string.Format( "({0},{1},{2})",
- RealString( p.X * _foot_to_mm ),
- RealString( p.Y * _foot_to_mm ),
- RealString( p.Z * _foot_to_mm ) );
- }
Запустив команду на тестовом проекте, мы увидим два сообщения, по одному для каждой стены. Вот такое сообщение для красной стены:
И точно такое же для синей:
Примечание: в исходной статье не были представлены файлы проектов А и В. Я создал подобные файлы, но координаты там немного различаются. Файлы проектов, используемых в статье, можно скачать по ссылке ниже.
Надеюсь я полностью ответил на ваш вопрос.
Скачать исходный код и файлы проектов можно по этой ссылке.
Обсуждение: http://adn-cis.org/forum/index.php?topic=315
Опубликовано 10.11.2013Отредактировано 10.11.2013 в 11:08:17