2022년 12월 25일 일요일

파라메트릭 모델링 지원 Revit Dynamo 개발 역사, 사용법 및 JSON에서 Revit BIM 객체 생성 파이썬 코딩하기

이 글은 파라메트릭 모델링을 지원하는 Revit Dynamo 개발역사, 사용법을 간략히 설명한다. 그리고, JSON에 저장된 객체정보로 부터 Revit BIM(Building Information Modeling) 객체를 자동생성하는 다이나모 파이썬 스크립트를 간단히 개발해본다. 이를 통해, 다이나모 장단점을 이해하고, 다음과 같은 사용법을 이해할 수 있다. 
  • 플로우 프로그래밍 방법
  • 다이나모 API와 패키지
  • 다이나모 파이썬 프로그래밍 및 디버깅 방법
  • 다이나모에서 JSON 파일 사용 방법
Revit Dynamo 기본 개념
래빗 다이나모는 3차원 파라메트릭 디자인에서 영역을 키워가고 있는 라이노(Rhino)의 그래스호퍼(Grasshopper)에 대응하기 위해 개발된 비쥬얼 플로우(flow)기반 프로그래밍 도구이다. 오토데스크에서 이를 주도한 Matt Jezyk는 수치 계산에 기반한 BIM 개념(Computational BIM)으로 다이나모를 개발했다고 한다(2013년). 참고로, 그는 다이나모를 이전부터 오픈소스운동에 대한 신념으로 개발해왔다.

다이나모 github 사이트

처음 다이나모 릴리즈 시에는 많은 버그와 문제가 있었으나, 오토데스크의 지원과 개발로 지금은 많이 안정화되었고, 성능도 좋아졌다. 아직 그래스호퍼 많큼 품질 좋은 애드인이 부족하지만, 이 부분도 개선되고 있다.

참고로, 플로우 프로그래밍은 텍스트로 코딩하여 프로그램을 개발하는 방식이 아닌, 제공된 기능 도구에서 드래그&드롭 식으로 캔버스에 배치해, 각각의 기능 실행 순서를 그래프로 연결해 프로그램을 개발하는 방식이다. 

플로우 프로그래밍 예시

이 방식의 장점은 특정 프로그래밍 언어를 잘 몰라도, 쉽게 프로그램 개발이 가능하다는 점이다. 다만, 텍스트에서 20줄 정도 소스코드가 플로우 프로그래밍 캔버스에서는 너무 복잡하게 보여진다는 점과 유지관리가 어렵다는 점이다. 아울러, 최신 라이브러리, 디버깅 도구 등 사용에 제한이 있다.

사용법
래빗과 래빗 컨텐츠를 설치한다. 이때, 다이나모도 같이 설치된다. 다음 리본 메뉴를 실행하면, 다이나모가 실행된다. 
다이나모 실행 버튼
다이나모 윈도우

다이나모 New 버튼을 클릭하면, 다이나모 프로그램이 다음과 같이 보여진다. 
다이나모 프로그램 UI

UI는 상단 메뉴, 왼쪽 도구 및 애드인 패널, 중간 빈 캔버스, 왼쪽 하단 플로우 프로그램 실행 모드(자동 및 수동), 우측 상단 모드 선택 메뉴 등으로 구성된다. 

라이노 그래스호퍼처럼, 실행 결과가 엔티티 객체로 렌더링 및 생성되므로, 이를 확인할 수 있는 모드가 필요하다. 이를 위해, 다이나모 캔버스는 모델 모드, 플로우 프로그래밍 모드의 두 가지가 있고, 캔버스의 우측 상단 메뉴를 통해 스위치할 수 있다.
모드 전환 스위치 메뉴

프로그래밍 방법은 매우 간단하다. 왼쪽 도구 메뉴에서 필요한 도구를 선택하고, 클릭하면, 캔버스에 자동으로 도구가 노드로 배치된다. 캔버스에서 컨텍스트 메뉴를 호출해 배치하기 원하는 기능 노드를 선택할 수도 있다. 다음과 같이 원하는 노드들을 배치한 후, 각 노드의 입출력 포트를 연결해 와이어링(wiring)해 주면 된다. 이후, 좌측 아래실행 버튼을 클릭해, 엔티티 객체 등을 생성하면 된다. 
두개 시점, 종점 좌표들을 생성해 선들을 생성하는 프로그램 예시

다이나모는 그래스호퍼처럼 플로우 프로그래밍 가능하도록, C++와 같은 프로그래밍 언어의 제어문, 수치 계산, 파일 입출력 등을 기본 제공한다. Revit API가 도구화되어 있어, 계산된 데이터에 의한 파라메트릭한 BIM 객체 생성 기능을 제공한다. 또한, 개발자가 외부에서 작성한 애드인 도구들을 추가해 사용할 수 있다. 좀 더 상세한 사용법은 다음을 참고한다.

플로우 프로그래밍 한계점
앞서 언급한 바와 같이, 노드와 노드의 입출력 포트를 연결해 프로그래밍하는 방식은 접근하기 쉬우나, 프로그램 구조가 조금만 복잡해지면, 유지보수하기 어려울만큼 노드 그래프의 구조를 알아보기 어려워진다. 
노드 기반 플로우 프로그래밍 Hell 

이외에, 이 상태에서 에러가 발생하면, 디버깅이 거의 불가능하다는 것도 큰 문제다. 발전하는 최신 기술과 라이브러리를 사용하지 못하는 것은 덤이다. 

이런 문제를 다이나모의 파이썬 스크립트 노드를 이용해 일부 해결할 수 있다. 

다이나모 파이썬 기반 JSON에서 Revit BIM 객체 자동 생성
앞에 언급된 문제를 피해, 기본적인 부분만 플로우 프로그래밍하고, 나머지 복잡한 부분은 파이썬으로 코딩해 본다. 

이 예시는 JSON 입력 파일로 부터, 데이터를 읽어, 이를 Revit BIM 객체로 생성하는 방법을 간단히 보여준다. 알고리즘은 다음과 같다. 
  1. BIM 객체 생성할 Revit Family 및 Level 선택
  2. input.json 파일 읽기
  3. 파일에서 생성할 객체 정보 획득
  4. 객체를 패밀리로 부터 생성하고, 객체 리스트를 만듬
  5. 객체 리스트를 이용해, Revit BIM 객체 출력
input.json 파일은 다음과 같이 저장되어 있다고 가정한다. 
{
"objects": [
{
"data": "data_1",
"bbox": [[0, 0, 0], [100, 100, 100]] 
},
{
"data": "data_2",
"bbox": [[2000, 2000, 0], [2100, 2100, 100]] 
}
]
}

다음과 같이 Family Types, Levels, Python script, Element.Geometry, Watch 노드를 캔버스에 배치하고, 입출력 포트를 서로 연결한다. Python script 노드 이름을 목적에 맞게 create objects로 수정하고, '+' 버튼을 클릭해 IN 포트를 하나 더 추가한다.
JSON to BIM object 프로그래밍된 노드 그래프

Family Types노드와 Levels 입력 콤보박스를 적절히 선택한다. 그리고, Python script 노드의 '...' 메뉴에서 Edit 메뉴를 선택한다.
파이썬 스크립트 창

다음과 같이 파이썬 편집창에서 코딩한다. 
# Load the Python Standard and DesignScript Libraries
import sys, clr, math, os, json # 라이브러리 임포트
clr.AddReference('ProtoGeometry')
clr.AddReference('RevitNodes')
clr.AddReference("RevitAPIUI")
clr.AddReference('DynamoRevitDS')
clr.AddReference('RevitServices')

from Autodesk.DesignScript.Geometry import *
from Autodesk.Revit.UI import *
# from Autodesk.Revit.DB import * # error. not support
from Revit.Elements import *
from RevitServices.Persistence import DocumentManager
from RevitServices.Transactions import TransactionManager
from Autodesk.Revit.UI.Selection import *
from io import StringIO
import Dynamo 

# input
sys.stdout = StringIO()  # 디버깅 위해 표준출력을 StringIO로 설정
print('begin')

doc = DocumentManager.Instance.CurrentDBDocument  
uiapp = DocumentManager.Instance.CurrentUIApplication
TransactionManager.Instance.EnsureInTransaction(doc)  # 트랜잭션 구간 시작

ftype = IN[0]   # 노드 1번 입력. 패밀리 유형
level = IN[1]    # 노드 2번 입력. 레벨

# define functions
def create_objects(objects_json):   # 객체 생성 함수 정의. JSON 데이터 입력 받음
    input_objects = objects_json['objects']
    
    objs = []
    for input_obj in input_objects:   # JSON 내 각 객체 정보 획득
        data = input_obj['data']
        bbox = input_obj['bbox']
        pt1 = bbox[0]
        pt2 = bbox[1]

        pt = Point.ByCoordinates(pt1[0], pt1[1], pt1[2])
        # TaskDialog.Show("debug", str(pt)) 
        
        obj = FamilyInstance.ByPointAndLevel(ftype, pt, level)
        objs.append(obj)   # 패밀리에서 BIM 객체 생성
    return objs  # 리스트 리턴

# define variables
dyn = Dynamo.Applications.DynamoRevit()
cur_wspace = dyn.RevitDynamoModel.CurrentWorkspace
curpath = cur_wspace.FileName # os.getcwd()
path_fname = os.path.split(curpath)

# 현재 다이나모 소스 파일 저장된 폴더에 저장된 input.json 파일 읽기
fname = path_fname[0] + '\input.json'
objs = []
objects_json = {}
try:    # 디버깅하기 쉽게 exception 처리
    with open(fname, "r") as read_file:
        objects_json = json.load(read_file)  # JSON 파일 로딩
    objs = create_objects(objects_json)    # 객체 생성
except Exception as e:
    TaskDialog.Show("error", str(e))
        
# output 
OUT = objs  # 객체 리스트 리턴
    
TransactionManager.Instance.TransactionTaskDone()     # 트랜잭션 종료
print('end')

이를 실행하면, 다음과 같이, JSON 파일에서 BIM 객체들이 자동 생성된다. 이제 외부에 저장된 데이터에서 파라메트릭하게 객체들을 쉽게 생성할 수 있다.

디버깅을 위해, 예외처리가 되어 있어, 유지보수하기 편리하다. exception 발생하면, TaskDialog로 에러 메시지를 확인할 수 있도록 하였다.


마무리
이 글은 파라메트릭 모델링을 지원하는 Revit Dynamo의 개념 및 사용법을 설명한 후, JSON에서 Revit BIM 객체를 자동 생성하는 파이썬 스크립트를  코딩해 보았다. 

노드와 노드의 입출력 포트를 연결해 프로그래밍하는 방식은 접근하기 쉬우나, 프로그램 구조가 조금만 복잡해지면, 유지보수하기 어렵다. 복잡도가 높은 부분은 적절히 파이썬으로 구현하면, 이런 문제를 개선할 수 있다. 다만, 다이나모는 아직도 예제 등 많은 부분에서 문서화되어 있지 않고, 버그가 많으며(파이썬 스크립트 에러 발생 시 래빗 재부팅 문제, 도움말 복사 안됨, Revit과 다이나모 API 충돌 등), 디버깅에 한계가 있다. 
구글링 검색 잘 안되는 다이나모 API(예제가 부족해 도움말로 추측해 사용해야 한다-.-)

여러 문제에도 불구하고, 다이나모는 강력한 오토데스크 BIM 개발도구 지원아래 오픈소스 프로젝트로부터 시작되어 많은 개발자들의 공헌으로 지금까지 꾸준히 개발되고 있다. 이런 점은 쓸만한 오픈소스가 많지 않은 국내 엔지니어링 산업계에 비해 많은 점을 느끼게 한다.

레퍼런스

댓글 없음:

댓글 쓰기