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

ADN Club => Revit API => Тема начата: Илья Дрягин от 17-03-2017, 14:41:10

Название: Получение нормали к поверхности стены
Отправлено: Илья Дрягин от 17-03-2017, 14:41:10
Здравствуйте!
Есть задачка над которой думаю уже несколько дней.
Имеется помещение (Room), окруженное стенами. Задача построить новые стены, которые будут параллельны имеющимся стенам по всей границе помещения и смещены на заданную дистанцию внутрь этого помещения.

Для создания стен необходимо задать кривые (Curve), остальные параметры (уровень, высота и т.д.) заданы.

Получить кривые сегментов границы помещения не сложно через:
Код - C# [Выбрать]
  1. SpatialElementBoundaryOptions opt = new SpatialElementBoundaryOptions();
  2. IList<IList<BoundarySegment>> segs = selectedroom.GetBoundarySegments(opt);

Код - C# [Выбрать]
  1. Curve newcurve = seg.GetCurve();

А вот дальше эту кривую надо сместить внутрь помещения wallLine.Move(translationVector). И тут возникла проблема с определением вектора (а точнее направления) для смещения.
По моим размышлениям надо получить вектор нормали поверхности геометрии помещения, относящейся к данному сегменту границы, либо нормаль поверхности стены, которой образован данный сегмент  границы. и каждый способ ведет к перебору пересечений всех поверхностей стены и поверхностей геометрии помещения и сравнивания их и то я еще не понял как это реализовать. Но может есть более простой способ?

Название: Re: Получение нормали к поверхности стены
Отправлено: Александр Ривилис от 17-03-2017, 15:50:18
Пока напомню про правила форматирования кода на форуме, которые у нас приняты и указаны у меня в подписи.
Название: Re: Получение нормали к поверхности стены
Отправлено: shss от 20-03-2017, 09:44:42
Это перемещение стены:

Код - C# [Выбрать]
  1. double moveDistance = 100;
  2. Line geomLine = Line.CreateBound(wallStartPoint, wallEndPoint); //создание прямой из полученных точек стены или кривой
  3. XYZ lineDirection = geomLine.Direction; //направление прямой
  4. XYZ normal = XYZ.BasisZ.CrossProduct(lineDirection).Normalize(); // нормаль к прямой
  5. XYZ transform = normal.Multiply(moveDistance); //минус определяет направление сдвига
  6. LocationCurve wallLine = wall.Location as LocationCurve;
  7. wallLine.Move(transform);
  8.  

Переделать под создание стены, достаточно просто.
Название: Re: Получение нормали к поверхности стены
Отправлено: Илья Дрягин от 21-03-2017, 13:03:04
Спасибо, но вопрос направления нормали полученной Вашим способом остается для меня открытым. Заранее не известно ориентация стены, создающей границу помещения и помещения могут быть с обоих сторон одной стены. В этом случае созданная стена в одном помещении сдвинется в нужную сторону, а вот в соседнем в обратную (наружу от границы помещения).
Название: Re: Получение нормали к поверхности стены
Отправлено: shss от 21-03-2017, 14:05:32
Тогда работайте с полученными сегментами.
Я вместо стен создал линии внутри комнаты:
Код - C# [Выбрать]
  1. foreach (ElementId id in selectedIds) {
  2.     Room room = doc.GetElement(id) as Room;
  3.     IList<IList<Autodesk.Revit.DB.BoundarySegment>> loops = room.GetBoundarySegments(new SpatialElementBoundaryOptions());
  4.     foreach (IList<Autodesk.Revit.DB.BoundarySegment> loop in loops) {
  5.         n = loop.Count;
  6.         int j = 0;
  7.         foreach (Autodesk.Revit.DB.BoundarySegment seg in loop) {
  8.             Element e = doc.GetElement(seg.ElementId) as Element;
  9.             string s = "Element property";
  10.             XYZ p = seg.GetCurve().GetEndPoint(0);
  11.             XYZ q = seg.GetCurve().GetEndPoint(1);
  12.             ModelLineCreation(uiapp, p, q, j);
  13.         }
  14.     }
  15. }
  16.  


Код - C# [Выбрать]
  1.  public ModelCurve ModelLineCreation(UIApplication app, XYZ startPoint, XYZ endPoint, int counter, string style = "") {
  2.             ModelCurve mc = null;
  3.  
  4.             Autodesk.Revit.DB.Document doc = app.ActiveUIDocument.Document;
  5.             View view = doc.ActiveView;
  6.  
  7.             using (Transaction tr = new Transaction(doc, "ModelLine creation")) {
  8.                 tr.Start();
  9.                 CurveArray ca = new CurveArray();
  10.                 XYZ origin = new XYZ(-1000, -1000, 0);
  11.                 Line mLine = Line.CreateBound(startPoint, endPoint);
  12.                 ca.Append(mLine);
  13.                 ca.Append(Line.CreateBound(mLine.GetEndPoint(1), origin));
  14.                 ca.Append(Line.CreateBound(origin, mLine.GetEndPoint(0)));
  15.                 Plane verticalGeometryPlane = app.Application.Create.NewPlane(ca);
  16.                 SketchPlane verticalSkplane = SketchPlane.Create(doc, verticalGeometryPlane);
  17.                 mc = doc.Create.NewModelCurve(mLine, verticalSkplane);
  18.  
  19.                 XYZ lineDirection = (Line.CreateBound(startPoint, endPoint)).Direction; ////// код из первого ответа
  20.                 XYZ normal = XYZ.BasisZ.CrossProduct(lineDirection).Normalize();
  21.                 XYZ transform = normal.Multiply(0.5);
  22.                 LocationCurve mcLine = mc.Location as LocationCurve;
  23.                 mcLine.Move(transform);
  24.  
  25.                 XYZ baseVec1 = XYZ.BasisX;
  26.                 XYZ upVec1 = XYZ.BasisZ;
  27.                 double lineWidth = 1.0/12.0;
  28.                 TextNoteOptions to = new TextNoteOptions();
  29.                 to.HorizontalAlignment = HorizontalTextAlignment.Center;
  30.                 to.TypeId = doc.GetDefaultElementTypeId(ElementTypeGroup.TextNoteType);
  31.                
  32.                 if (style != "") {
  33.                     GraphicsStyle debugStyle = GetLineStyleByName(doc, mc, style);
  34.                     mc.LineStyle = debugStyle;
  35.                 }
  36.  
  37.                 tr.Commit();
  38.             }
  39.             return mc;
  40.         }
  41.  
  42.         public GraphicsStyle GetLineStyleByName(Autodesk.Revit.DB.Document doc, CurveElement element, string styleName) {
  43.             foreach (Element style in GetLineStyles(doc, element)) {
  44.                 GraphicsStyle anyStyle = style as GraphicsStyle;
  45.                 if (anyStyle.Name == styleName) {
  46.                     if (anyStyle.GraphicsStyleType == GraphicsStyleType.Projection) {
  47.                         return anyStyle;
  48.                     }
  49.                 }
  50.             }
  51.  
  52.             return null;
  53.         }
  54.         public List<GraphicsStyle> GetLineStyles(Autodesk.Revit.DB.Document doc, CurveElement element) {
  55.             List<GraphicsStyle> styles = new List<GraphicsStyle>();
  56.             ICollection<ElementId> lineIDs = element.GetLineStyleIds();
  57.             foreach (ElementId lineID in lineIDs) {
  58.                 Element elem = doc.GetElement(lineID);
  59.                 if (elem != null) {
  60.                     GraphicsStyle style = elem as GraphicsStyle;
  61.                     if (style != null)
  62.                         styles.Add(style);
  63.                 }
  64.             }
  65.             return styles;
  66.         }
  67.  

В этом случае выбирая любую комнату, все линии будут внутри.
(https://adn-cis.org/forum/proxy.php?request=http%3A%2F%2Fi90.fastpic.ru%2Fbig%2F2017%2F0321%2F61%2F4214e4441743df18b13d56dc026ca561.png&hash=02fd59f92d7b9c5a05c3f512aa62948c) (http://fastpic.ru/)
Со стенами та же история. Только их еще надо будет подрезать правильно, но вообщем это не проблема, потому что будет пересечение.

Название: Re: Получение нормали к поверхности стены
Отправлено: Илья Дрягин от 21-03-2017, 15:10:16
Огромное спасибо, буду тестить
Название: Re: Получение нормали к поверхности стены
Отправлено: shss от 21-03-2017, 15:19:36
Не за что, но будьте аккуратны в любом случае, так как сегменты, это очень специфичная область.
Одна стена может состоять из двух и более сегментов (например врезка стены с другой стороны комнаты образует два сегмента стены).
Ну и как на картинке выше, сегменты могут не пересекаться, соответственно нужно будет продлевать их, для получения точки пересечения, и построения стены.