Efektywne łączenie elementów w Dynamo

[Podobny problem w C# prezentowaliśmy w innym poście]

[Przygotowaliśmy także gotowy node dla Dynamo rozwiązujący ten problem, więcej tu]


Masowe łączenie elementów w Revicie może być bardzo pracochłonną czynnością. Jest to na pewno coś co większość z nas chętnie zoptymalizowałaby przy pomocy Dynamo. Szczęśliwie bez problemu możemy znaleźć dodatkowe węzły Dynamo pozwalające na łączenie elementów. Możemy też skorzystać z funkcji Revit API w Pythonie:

JoinGeometryUtils.JoinGeometry(doc,a,b)

gdzie doc to aktywny dokument a a i b to elementy do połączenia.

Problemy (z wydajnością) zaczynają się jednak przy większych i bardziej skomplikowanych modelach. Jeśli stworzymy skrypt który będzie próbował połączyć np. każdą ścianę z każdym możliwym stropem, to nie tylko jego wykonanie zajmie dużo czasu, ale także zwróci wiele błędów. Stanie się tak ponieważ Dynamo będzie próbowało połączyć także te elementy, które w ogóle się nie stykają, a wręcz znacznie od siebie oddalone. To nie może być efektywne podejście 🙂

Przed próbą połączenia elementów warto więc sprawdzić czy ich geometrie się przenikają. Często jednak obiekty mają skomplikowane kształty i takie sprawdzenie również może być dość pracochłonne (dla skryptu). Dlatego w poniższym rozwiązaniu proponuję dla zadanych elementów wykonywać dodatkowe, wstępne sprawdzenie, które pozwoli określić czy elementy te w ogóle znajdują się w pobliżu i mają szansę przenikać.

Każdy element modelowy w Revicie posiada tzw. BoundingBox – przestrzenną obwiednie, która de facto jest najmniejszym pudełkiem mogącym pomieścić ten element. W dość prosty (i szybki) sposób jesteśmy w stanie sprawdzić czy takie pudełka, zawierające dwa różne elementy, się przenikają lub stykają. Wykonanie takiej operacji dla prostopadłościanów jest dużo efektywniejsze niż dla dokładnej geometrii.

Poniższy kod jako parametry przyjmuje dwie listy elementów. Następnie testuje każdy element z pierwszej listy z każdym elementem z drugiej – czy ich pudełka się przenikają. Zwracanym rezultatem jest lista par przenikających się elementów.

import clr

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

def overlap1D(a1, a2, b1, b2):
  if a2>=b1 and b2>=a1:
    return True
  return False
  
def bbIntersect(bbA, bbB):
  return overlap1D(bbA.Min.X,bbA.Max.X,bbB.Min.X,bbB.Max.X) and overlap1D(bbA.Min.Y,bbA.Max.Y,bbB.Min.Y,bbB.Max.Y) and overlap1D(bbA.Min.Z,bbA.Max.Z,bbB.Min.Z,bbB.Max.Z)

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

output = []

for a in listA:
  bbA = a.get_BoundingBox(None)
  if not bbA is None:
    for b in listB:
      bbB = b.get_BoundingBox(None)
      if not bbB is None:
        if bbIntersect(bbA,bbB):
          output.append([a,b])

#Assign your output to the OUT variable.
OUT = output

W ten sposób otrzymujemy listę par elementów, co do których mamy już dość poważne podejrzenie że mogą się przenikać lub stykać.

Ten przykładowy skrypt (do pobrania na końcu posta) połączy nam wszystkie ściany i posadzki w projekcie:

Ostatni węzeł Join, również zawiera kod w Pythonie łączący dwie listy elementów:

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

clr.AddReference("RevitServices")
import RevitServices
from RevitServices.Persistence import DocumentManager
from RevitServices.Transactions import TransactionManager
#The inputs to this node will be stored as a list in the IN variables.
list_a = UnwrapElement(IN[0])
list_b = UnwrapElement(IN[1])

doc = DocumentManager.Instance.CurrentDBDocument
TransactionManager.Instance.EnsureInTransaction(doc)

output = []

for a,b in zip(list_a,list_b):
	try:
		JoinGeometryUtils.JoinGeometry(doc,a,b)
		output.append("OK")
	except Exception,e:
		output.append(str(e))


TransactionManager.Instance.TransactionTaskDone()

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

3 thoughts on “Efektywne łączenie elementów w Dynamo

  1. Dzień dobry Maciej,
    Bardzo dobra strona i dziękuję za pomysły z rozwiązaniami jak przyspieszyć pracę.
    Sam jestem BIM managerem i trochę usprawniam prace w biurze. Zrobiłem ostatnio podobny skrypt do łączenia geometrii w modelu, ale tyko przy użyciu OOTB Dynamo i niestety nie łączy mi wszystkich, zawsze kilka geometrii zostaje do połączenia ręcznie.
    Ale jak na razie nie wyszedłem poza Dynamo – do Pythona.
    I tu moje bardziej ogólne pytanie/prośba: Czy mógłbyś napisać coś więcej (może artykuł?) od czego zacząć naukę Pythona, żeby używać go w skryptach? Jest co prawda cała masa kursów programowania, ale właśnie przez tą ilość nie mam pojęcia jaką ścieżkę wybrać, zwłaszcza pod Revitem i Dynamo.
    Będę wdzięczny za jakiekolwiek informacje.
    Pozdrawiam
    Piotr

    1. Dziekuję za komentarz:)
      Mam jednak nieco problem z konkretną odpowiedzią…sam programowanie w Revicie zaczynałem od C# i tu nieoceniony jest blog https://thebuildingcoder.typepad.com/
      Z czasem gdy potrzebowałem napisać coś w dynamo w zasadzie tłumaczyłem skrypty z C#, znając jedynie absolutne podstawy Pythona.
      Na pewno jednak Python jest językiem przystępniejszym i faktycznie warto od niego zacząć – zwłaszcza, że materiałów dotyczących użycia Pythona w Dynamo jest coraz więcej, głównie na forum https://forum.dynamobim.com/
      Pewne podstawy dotyczące Pythona w tym kontekście zawarte również są np. w tym tutorialu https://dynamopythonprimer.gitbook.io/dynamo-python-primer/

      Aczkolwiek uważam, że naukę programowania warto zacząć w oderwaniu od konkretnego zastosowania, tak aby przyswoić ogólne koncepty takie jak zmienne, obiekty, klasy, pętle etc. – a później do tego dołożyć jednak Revita, który jest dość zagmatwany od strony programistycznej.

      Co prawda nie uczyłem się tu podstaw programowania/Pythona, ale często pomocną była mi strona Towards Data Science. Jak nazwa wskazuje jest skierowana do innych zastosowań, jednak oferuje też ogólną wiedzę z programowania w Pythonie. Np. podstawy tu:
      https://towardsdatascience.com/a-beginners-guide-to-python-for-data-science-60ef022b7b67

      Mam nadzieję, że powyższe jest choć trochę pomocne 🙂 W razie czego proszę dalej śmiało pytać.
      Maciek

  2. Maciej,
    Dziękuję Ci bardzo za odpowiedź, wyczerpuje temat 🙂 o takie linki mi chodziło, już wiem co robić 🙂
    pozdrawiam
    Piotr

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