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

07/09/2013

Поиск соседних комнат

Проблема была озвучена, а также решена Эриком Эрикссоном (Erik Eriksson) из компании  White Arkitketer AB , которому понадобилось определить соседние комнаты для любой заданной комнаты.

Эта статья является дополнением к очень давнему обсуждению комната и смежные стены от января 2009 года, в котором мы просто рассматривали как определить соседние стены для заданной комнаты.

В Revit API на данный момент появились более мощные инструменты для такого вида анализа, позволяя нам очень просто узнать соседние комнаты.

В примере кода, представленном ниже,

Вопрос: Я пытаюсь найти комнаты, которые являются смежными по отношению к другим комнатам. Я предполагаю, что псевдокод должен быть таким:

  • Получить все комнаты в проекте
  • Для каждой комнаты найти все смежные комнаты (т.е. комнату по другую сторону стены) и стены разделяющие их

Есть ли какой-нибудь метод, который позволяет найти смежные комнаты? Сначала я думал использовать ReferenceIntersector, но он не работает с комнатами.

Затем я думал об использовании метода Room.IsPointInRoom и передать ему в качестве параметра координаты точки, находящейся на обратной стороне стены. Но это означает нужно перебрать все стены для каждой комнаты проекта. Я чувствую, что это займет очень много времени на большом проекте, например, если в проекте 1000 комнат с 6 стенами каждая, то потребуется 6 000 000 операций.

Ответ: API не предоставляет прямого метода, который позволял бы получить соседние комнаты.

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

То, что вам нужно по сути является одним из видов структуры графов.

Вы можете разделить двумерную поверхность заданного уровня на полигоны, которые попадают в один из трех классов: внутри комнаты, внутри стены или снаружи здания. Если затем вы уберете стены, все соседние с комнатой полигоны будут являться смежными комнатами.

Если у вас есть какая-нибудь библиотека для работы с двумерной графикой, которая сможет автоматически сгенерировать графы соседних полигонов, то это может быть довольно привлекательным и надежным способом для решение поставленной задачи.

Как извлечь требуемые данные более эффективно без использования анализов двумерной геометрии для меня тоже пока не ясно.

Метод Room.IsPointInRoom, который предложили, определенно не является подходящим.

Наиболее эффективный алгоритм можно осуществить с помощью метода Document.GetRoomAtPoint. Чтобы определить координаты точек, которые необходимо передать в качестве параметра, нужно найти координаты обратной стороны стены и немного углубиться в соседнее пространство. Таким образом, полученные координаты будут находиться в границах соседней комнаты.

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

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

Вот ссылки на похожие статьи (на англ.):

Отклик на ответ: Метод Document.GetRoomAtPoint работает замечательно!

Я прошелся по всем границам всех комнат и посмотрел есть ли комната по другую сторону стены.

Вот метод, который я использую для нахождения комнаты по другую сторону стены:

Код - C#: [Выделить]
  1.   /// <summary>
  2.   /// Return the neighbouring room to the given one
  3.   /// on the other side of the midpoint of the given
  4.   /// boundary segment.
  5.   /// </summary>
  6.   Room GetRoomNeighbourAt(
  7.     BoundarySegment bs,
  8.     Room r )
  9.   {
  10.     Document doc = r.Document;
  11.  
  12.     Wall w = bs.Element as Wall;
  13.  
  14.     double wallThickness = w.Width;
  15.  
  16.     double wallLength = ( w.Location as
  17.       LocationCurve ).Curve.Length;
  18.  
  19.     Transform derivatives = bs.Curve
  20.       .ComputeDerivatives(  0.5, true );
  21.  
  22.     XYZ midPoint = derivatives.Origin;
  23.  
  24.     Debug.Assert(
  25.       midPoint.IsAlmostEqualTo(
  26.         bs.Curve.Evaluate( 0.5, true ) ),
  27.       "expected same result from Evaluate and derivatives" );
  28.  
  29.     XYZ tangent = derivatives.BasisX.Normalize();
  30.  
  31.     XYZ normal = new XYZ( tangent.Y,
  32.       tangent.X * ( -1 ), tangent.Z );
  33.  
  34.     XYZ p = midPoint + wallThickness * normal;
  35.  
  36.     Room otherRoom = doc.GetRoomAtPoint( p );
  37.  
  38.     if( null != otherRoom )
  39.     {
  40.       if( otherRoom.Id == r.Id )
  41.       {
  42.         normal = new XYZ( tangent.Y * ( -1 ),
  43.           tangent.X, tangent.Z );
  44.  
  45.         p = midPoint + wallThickness * normal;
  46.  
  47.         otherRoom = doc.GetRoomAtPoint( p );
  48.  
  49.         Debug.Assert( null == otherRoom
  50.             || otherRoom.Id != r.Id,
  51.           "expected different room on other side" );
  52.       }
  53.     }
  54.     return otherRoom;
  55.   }

Выражением If я проверяю, что смотрю в верном направлении в соответствии с направлением стены. Я направляю вектор в противоположную сторону если в первой попытке я получил тот же самый результат.

Большое спасибо Эрику за обсуждение и решение данного вопроса.

Я добавил этот код в примеры The Building Coder в виде новой команды CmdRoomNeighbours.

Скачать пример кода и пример проекта можно по ссылке  version 2014.0.103.0 

Источник: http://thebuildingcoder.typepad.com/blog/2013/09/room-neighbours.html

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

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