Wymiarowanie ścian kurtynowych z API i Dynamo

Dziś krótki post o tym jak przeprowadzić automatyzację wymiarowania ścian kurtynowych. Na początek na potrzeby posta załóżmy, że jako danymi wyjściowymi dysponujemy ścianą kurtynową, linią wzdłuż której chcemy umieścić wymiary oraz widokiem. Do stworzenia nowej linii wymiarowej w Revicie służy funkcja:

doc.Create.NewDimension(view,line,refArray);

Gdzie „doc” to aktywny dokument Revita, „view” to widok w którym chcemy umieścić wymiar, „line” linia położenia wymiaru, „refArray” lista referencji czyli odniesień do wymiarowanych obiektów/linii.

Aby uzyskać efekt taki jak na przykładzie powyżej, potrzebne są nam dwa rodzaje referencji:
-skrajne krawędzie ściany
-osie pionowe układu ściany

Pierwsze z nich uzyskamy bezpośrednio z geometrii ściany. W tym celu musimy pobrać obiekt GeometryElement naszej ściany:

Options options = this.Application.Create.NewGeometryOptions();
options.ComputeReferences = true;
options.IncludeNonVisibleObjects = true;
   
GeometryElement geoElement = w.get_Geometry(options);

Gdzie „w” to nasza ściana, a „options” to opcje wyjściowe dla funkcji pobierania geometrii (get_Geometry()). W opcjach ustawiamy, jak powyżej, uwzględnienie obiektów niewidocznych oraz referencji do obiektów.

Następnie przeszukujemy pobrany geoElement pod kątem obiektów typu Solid. W dalszej kolejności sprawdzamy kierunek (wektor normalny) każdej ze ścian bryły (Solid). Jeśli jest on równoległy do naszej wyjściowej linii to zapisujemy referencję do danej ściany w zmiennej (refArray). Wygląda to tak:

foreach(GeometryObject obj in geoElement){
  Solid s = obj as Solid;
  if(s!=null) {
    foreach(Face f in s.Faces){
      PlanarFace pf = f as PlanarFace;
      if(pf!=null) {
        XYZ faceNormal = pf.FaceNormal;
        if(isParallel(faceNormal,line.GetEndPoint(1)-line.GetEndPoint(0))) {
          refArray.Append(f.Reference);
        }
      }
    }
  }
}

Pozostało nam teraz pobrać referencje wynikające z układu osi ściany kurtynowej (grid lines). Dostęp do pionowych osi ściany uzyskujemy poprzez funkcję:

ICollection gridIds = w.CurtainGrid.GetVGridLineIds();

Powyższa funkcja nie zwraca samych obiektów, a ich numery Id. Na podstawie takiego numeru musimy pobrać każdą z osi z dokumentu i wyszukać w niej geometryczny obiekt linii. Referencję do takiej linii zapisujemy, podobnie jak powyżej, w zmiennej (refArray). Ten fragment kodu wygląda następująco:

foreach(ElementId gridId in gridIds) {
  CurtainGridLine gridLine = doc.GetElement(gridId) as CurtainGridLine;
  if(gridLine!=null) {
    GeometryElement gridGeo = gridLine.get_Geometry(options);
    foreach(GeometryObject obj in gridGeo) {
      Line l = obj as Line;
      if(l!=null) refArray.Append(l.Reference);
    }
  }
}

Całość naszej funkcji może wyglądać natomiast tak:

private void horizontalDimension(Document doc, View view, Wall w, Line line) {
                        
  ReferenceArray refArray = new ReferenceArray();
            
  Options options = this.Application.Create.NewGeometryOptions();
  options.ComputeReferences = true;
  options.IncludeNonVisibleObjects = true;
            
  GeometryElement geoElement = w.get_Geometry(options);
            
  //get side references            
  foreach(GeometryObject obj in geoElement){
    Solid s = obj as Solid;
    if(s!=null) {
      foreach(Face f in s.Faces){
        PlanarFace pf = f as PlanarFace;
        if(pf!=null) {
          XYZ faceNormal = pf.FaceNormal;
          if(isParallel((faceNormal,line.GetEndPoint(1)-line.GetEndPoint(0))) {
            refArray.Append(f.Reference);
          }
        }
      }
    }
  }
            
  //get grid references            
  ICollection<ElementId> gridIds = w.CurtainGrid.GetVGridLineIds();
            
  foreach(ElementId gridId in gridIds) {
    CurtainGridLine gridLine = doc.GetElement(gridId) as CurtainGridLine;
    if(gridLine!=null) {
      GeometryElement gridGeo = gridLine.get_Geometry(options);
      foreach(GeometryObject obj in gridGeo) {
        Line l = obj as Line;
        if(l!=null) refArray.Append(l.Reference);
      }
    }
  }
            
  using(Transaction t = new Transaction(doc,"horizontal dimension")) {                      
    t.Start();
    doc.Create.NewDimension(view,line,refArray);
    t.Commit();
  }
}

Możliwe jest również wykonanie analogicznych operacji wewnątrz Dynamo, przy pomocy odpowiedniego węzła Python Script. Przepisany kod wyglądałby tak:

import clr

#The inputs to this node will be stored as a list in the IN variables.
wall = UnwrapElement(IN[0])
lineElement = UnwrapElement(IN[1])
view = UnwrapElement(IN[2])

clr.AddReference("RevitAPI")
from Autodesk.Revit.DB import *

clr.AddReference("RevitServices")
import RevitServices
from RevitServices.Transactions import TransactionManager
from RevitServices.Persistence import DocumentManager

def isParallel(v1,v2):
  return v1.CrossProduct(v2).IsAlmostEqualTo(XYZ(0,0,0))

line = lineElement.GeometryCurve
lineDir = line.GetEndPoint(1) - line.GetEndPoint(0)

refArray = ReferenceArray()

doc = DocumentManager.Instance.CurrentDBDocument

options = Options()
options.ComputeReferences = True
options.IncludeNonVisibleObjects = True

geoElement = wall.get_Geometry(options)

#get side references
for obj in geoElement:
  if isinstance(obj,Solid):
    for f in obj.Faces:
      faceNormal = f.FaceNormal
      if isParallel(faceNormal,lineDir):
        refArray.Append(f.Reference)
    
    
#get grid references
for id in wall.CurtainGrid.GetVGridLineIds():
  gridLine = doc.GetElement(id)
  gridGeo = gridLine.get_Geometry(options)
  for obj in gridGeo:
    if isinstance(obj,Line):
      refArray.Append(obj.Reference)


TransactionManager.Instance.EnsureInTransaction(doc)
doc.Create.NewDimension(view, line, refArray)
TransactionManager.Instance.TransactionTaskDone()

#Assign your output to the OUT variable.
OUT = 0
Posts created 34

Dodaj komentarz

Twój adres email nie zostanie opublikowany.

Related Posts

Begin typing your search term above and press enter to search. Press ESC to cancel.

Back To Top