B
bim-visual-programming-automation
bim-visual-programming-automation について
Autodesk Revit と Dynamo の API を使って BIM ワークフローを自動化するスキルです。ビジュアルプログラミングのスクリプトと Python ノードで、要素データ、変更、集計表、外部データ連携、数量拾いを扱います。
主な機能
- 01要素データの抽出
- 02要素の一括変更
- 03集計表の生成
- 04パラメーター管理
- 05データのインポートとエクスポート
- 06数量拾いの自動化
活用シーン
- 01壁データの Excel 出力
- 02Revit パラメーターの一括更新
- 03カスタム集計表の作成
- 04数量拾いの作成
インストール
コマンドをコピーしてターミナルで実行します。
$
npx skills add https:/ / github.com/ datadrivenconstruction/ ddc_skills_for_ai_agents_in_construction --skill bim-visual-programming-automationインストール後、Claude Code で/bim-visual-programming-automationを入力して読み込まれたか確認します。
同梱ファイルclaw.jsoninstructions.md
詳細
BIM ビジュアルプログラミングの自動化
概要
このスキルは、BIM ワークフローを自動化するためのビジュアルプログラミングスクリプトと Python ノードを提供します。データの抽出、要素の一括変更、集計表の生成、外部システムとの連携が可能です。
注: 例では Autodesk® Revit® と Dynamo™ の API を使用しています。Autodesk、Revit、Dynamo は Autodesk, Inc. の登録商標です。
主な機能:
- 要素の一括変更
- データのエクスポート/インポート
- 集計表の生成
- パラメーター管理
- 外部データ連携
- QTO の自動化
クイックスタート(Dynamo Python)
# Dynamo Python Script - Export all walls to Excel
import clr
clr.AddReference('RevitAPI')
clr.AddReference('RevitServices')
from RevitServices.Persistence import DocumentManager
from Autodesk.Revit.DB import FilteredElementCollector, BuiltInCategory
doc = DocumentManager.Instance.CurrentDBDocument
# Get all walls
collector = FilteredElementCollector(doc)
walls = collector.OfCategory(BuiltInCategory.OST_Walls).WhereElementIsNotElementType().ToElements()
# Extract data
wall_data = []
for wall in walls:
wall_data.append({
'id': wall.Id.IntegerValue,
'name': wall.Name,
'length': wall.get_Parameter(BuiltInParameter.CURVE_ELEM_LENGTH).AsDouble() * 0.3048,
'area': wall.get_Parameter(BuiltInParameter.HOST_AREA_COMPUTED).AsDouble() * 0.0929
})
OUT = wall_data
要素データの抽出
包括的な要素抽出ツール
# Dynamo Python Node - Extract all element data
import clr
clr.AddReference('RevitAPI')
clr.AddReference('RevitServices')
clr.AddReference('RevitNodes')
from RevitServices.Persistence import DocumentManager
from Autodesk.Revit.DB import *
import Revit
clr.ImportExtensions(Revit.Elements)
doc = DocumentManager.Instance.CurrentDBDocument
def get_element_data(element):
"""Extract data from Revit element"""
data = {
'id': element.Id.IntegerValue,
'category': element.Category.Name if element.Category else None,
'name': element.Name,
'level': None,
'parameters': {}
}
# Get level
level_param = element.get_Parameter(BuiltInParameter.SCHEDULE_LEVEL_PARAM)
if level_param:
level_id = level_param.AsElementId()
if level_id.IntegerValue > 0:
level = doc.GetElement(level_id)
data['level'] = level.Name if level else None
# Get all parameters
for param in element.Parameters:
try:
if param.HasValue:
if param.StorageType == StorageType.Double:
data['parameters'][param.Definition.Name] = param.AsDouble()
elif param.StorageType == StorageType.Integer:
data['parameters'][param.Definition.Name] = param.AsInteger()
elif param.StorageType == StorageType.String:
data['parameters'][param.Definition.Name] = param.AsString()
except:
pass
return data
def extract_category(category_enum):
"""Extract all elements of a category"""
collector = FilteredElementCollector(doc)
elements = collector.OfCategory(category_enum).WhereElementIsNotElementType().ToElements()
return [get_element_data(e) for e in elements]
# Extract structural elements
categories = [
BuiltInCategory.OST_Walls,
BuiltInCategory.OST_Floors,
BuiltInCategory.OST_StructuralColumns,
BuiltInCategory.OST_StructuralFraming,
BuiltInCategory.OST_Doors,
BuiltInCategory.OST_Windows
]
all_data = {}
for cat in categories:
cat_name = cat.ToString().replace('OST_', '')
all_data[cat_name] = extract_category(cat)
OUT = all_data
数量拾い出しスクリプト
# Dynamo Python - QTO Export
import clr
clr.AddReference('RevitAPI')
clr.AddReference('RevitServices')
from RevitServices.Persistence import DocumentManager
from Autodesk.Revit.DB import *
doc = DocumentManager.Instance.CurrentDBDocument
def get_qto_data():
"""Generate QTO data from model"""
qto = {}
# Walls
walls = FilteredElementCollector(doc).OfCategory(BuiltInCategory.OST_Walls)\
.WhereElementIsNotElementType().ToElements()
wall_qto = {}
for wall in walls:
wall_type = doc.GetElement(wall.GetTypeId())
type_name = wall_type.get_Parameter(BuiltInParameter.ALL_MODEL_TYPE_NAME).AsString()
if type_name not in wall_qto:
wall_qto[type_name] = {'count': 0, 'area': 0, 'length': 0}
wall_qto[type_name]['count'] += 1
area_param = wall.get_Parameter(BuiltInParameter.HOST_AREA_COMPUTED)
if area_param:
wall_qto[type_name]['area'] += area_param.AsDouble() * 0.0929 # sqft to m2
length_param = wall.get_Parameter(BuiltInParameter.CURVE_ELEM_LENGTH)
if length_param:
wall_qto[type_name]['length'] += length_param.AsDouble() * 0.3048 # ft to m
qto['Walls'] = wall_qto
# Floors
floors = FilteredElementCollector(doc).OfCategory(BuiltInCategory.OST_Floors)\
.WhereElementIsNotElementType().ToElements()
floor_qto = {}
for floor in floors:
floor_type = doc.GetElement(floor.GetTypeId())
type_name = floor_type.get_Parameter(BuiltInParameter.ALL_MODEL_TYPE_NAME).AsString()
if type_name not in floor_qto:
floor_qto[type_name] = {'count': 0, 'area': 0, 'volume': 0}
floor_qto[type_name]['count'] += 1
area_param = floor.get_Parameter(BuiltInParameter.HOST_AREA_COMPUTED)
if area_param:
floor_qto[type_name]['area'] += area_param.AsDouble() * 0.0929
vol_param = floor.get_Parameter(BuiltInParameter.HOST_VOLUME_COMPUTED)
if vol_param:
floor_qto[type_name]['volume'] += vol_param.AsDouble() * 0.0283 # cuft to m3
qto['Floors'] = floor_qto
return qto
OUT = get_qto_data()
一括変更
パラメーターの一括更新
# Dynamo Python - Batch update parameters
import clr
clr.AddReference('RevitAPI')
clr.AddReference('RevitServices')
from RevitServices.Persistence import DocumentManager
from RevitServices.Transactions import TransactionManager
from Autodesk.Revit.DB import *
doc = DocumentManager.Instance.CurrentDBDocument
def batch_update_parameter(elements, param_name, values):
"""Update parameter for multiple elements"""
TransactionManager.Instance.EnsureInTransaction(doc)
results = []
for elem, value in zip(elements, values):
try:
param = elem.LookupParameter(param_name)
if param and not param.IsReadOnly:
if param.StorageType == StorageType.String:
param.Set(str(value))
elif param.StorageType == StorageType.Double:
param.Set(float(value))
elif param.StorageType == StorageType.Integer:
param.Set(int(value))
results.append(True)
else:
results.append(False)
except Exception as e:
results.append(str(e))
TransactionManager.Instance.TransactionTaskDone()
return results
# Input from Dynamo nodes
elements = IN[0] # List of elements
param_name = IN[1] # Parameter name (string)
values = IN[2] # List of values
OUT = batch_update_parameter(elements, param_name, values)
要素の一括コピー
# Dynamo Python - Copy elements to levels
import clr
clr.AddReference('RevitAPI')
clr.AddReference('RevitServices')
from RevitServices.Persistence import DocumentManager
from RevitServices.Transactions import TransactionManager
from Autodesk.Revit.DB import *
from System.Collections.Generic import List
doc = DocumentManager.Instance.CurrentDBDocument
def copy_to_levels(elements, target_levels):
"""Copy elements to multiple levels"""
TransactionManager.Instance.EnsureInTransaction(doc)
copied = []
element_ids = List[ElementId]([e.Id for e in elements])
for level in target_levels:
# Calculate offset
source_level = doc.GetElement(elements[0].LevelId)
offset = XYZ(0, 0, level.Elevation - source_level.Elevation)
# Copy
new_ids = ElementTransformUtils.CopyElements(
doc, element_ids, offset
)
copied.extend([doc.GetElement(id) for id in new_ids])
TransactionManager.Instance.TransactionTaskDone()
return copied
elements = IN[0]
target_levels = IN[1]
OUT = copy_to_levels(elements, target_levels)
集計表の生成
カスタム集計表の作成
# Dynamo Python - Create view schedule
import clr
clr.AddReference('RevitAPI')
clr.AddReference('RevitServices')
from RevitServices.Persistence import DocumentManager
from RevitServices.Transactions import TransactionManager
from Autodesk.Revit.DB import *
doc = DocumentManager.Instance.CurrentDBDocument
def create_wall_schedule(schedule_name):
"""Create a wall schedule with QTO fields"""
TransactionManager.Instance.EnsureInTransaction(doc)
# Create schedule
schedule = ViewSchedule.CreateSchedule(
doc,
ElementId(BuiltInCategory.OST_Walls)
)
schedule.Name = schedule_name
# Add fields
definition = schedule.Definition
schedulable = definition.GetSchedulableFields()
# Find and add specific fields
field_names = ['Type', 'Level', 'Length', 'Area', 'Volume']
for sf in schedulable:
if sf.GetName(doc) in field_names:
definition.AddField(sf)
# Add sorting/grouping
type_field = None
for field in definition.GetFieldOrder():
if definition.GetField(field).GetName() == 'Type':
type_field = field
break
if type_field:
sorting = ScheduleSortGroupField(type_field, ScheduleSortOrder.Ascending)
sorting.ShowHeader = True
sorting.ShowFooter = True
definition.AddSortGroupField(sorting)
TransactionManager.Instance.TransactionTaskDone()
return schedule
schedule_name = IN[0]
OUT = create_wall_schedule(schedule_name)
外部データ連携
Excel からのデータのインポート
# Dynamo Python - Import Excel and update Revit
import clr
clr.AddReference('RevitAPI')
clr.AddReference('RevitServices')
from RevitServices.Persistence import DocumentManager
from RevitServices.Transactions import TransactionManager
from Autodesk.Revit.DB import *
# Requires Excel data as input from Dynamo Excel nodes
doc = DocumentManager.Instance.CurrentDBDocument
def update_from_excel(excel_data, id_column, param_columns):
"""Update Revit elements from Excel data"""
TransactionManager.Instance.EnsureInTransaction(doc)
results = []
for row in excel_data:
try:
# Get element by ID
elem_id = ElementId(int(row[id_column]))
element = doc.GetElement(elem_id)
if element:
row_result = {'id': elem_id.IntegerValue, 'updates': {}}
for col_name, col_index in param_columns.items():
param = element.LookupParameter(col_name)
if param and not param.IsReadOnly:
value = row[col_index]
if param.StorageType == StorageType.String:
param.Set(str(value))
elif param.StorageType == StorageType.Double:
param.Set(float(value))
row_result['updates'][col_name] = value
results.append(row_result)
except Exception as e:
results.append({'error': str(e)})
TransactionManager.Instance.TransactionTaskDone()
return results
excel_data = IN[0] # 2D list from Excel
id_column = IN[1] # Column index for element ID
param_columns = IN[2] # Dict: param_name -> column_index
OUT = update_from_excel(excel_data, id_column, param_columns)
Dynamo パッケージのワークフロー
QTO の全工程(Dynamo グラフノード)
1. Categories (Input)
|
2. All Elements of Category (Revit)
|
3. Element.GetParameterValueByName (Multiple parameters)
|
4. Python Script (Process and calculate)
|
5. List.Transpose
|
6. Data.ExportExcel
|
7. File Path (Output)
クイックリファレンス
| タスク | メソッド | パフォーマンス |
|---|---|---|
| 要素の取得 | FilteredElementCollector | 高速 |
| パラメーターの取得 | element.LookupParameter() | 高速 |
| パラメーターの設定 | TransactionManager が必要 | 中程度 |
| 要素のコピー | ElementTransformUtils | 中程度 |
| ビューの作成 | ViewSchedule.CreateSchedule | 低速 |
| 要素の削除 | Document.Delete | 高速 |
一般的なパラメーター名
# Built-in parameters for quantities
QUANTITY_PARAMS = {
'Length': BuiltInParameter.CURVE_ELEM_LENGTH,
'Area': BuiltInParameter.HOST_AREA_COMPUTED,
'Volume': BuiltInParameter.HOST_VOLUME_COMPUTED,
'Height': BuiltInParameter.WALL_USER_HEIGHT_PARAM,
'Width': BuiltInParameter.DOOR_WIDTH,
'Level': BuiltInParameter.SCHEDULE_LEVEL_PARAM
}
# Unit conversion (Imperial to Metric)
CONVERSIONS = {
'feet_to_meters': 0.3048,
'sqft_to_sqm': 0.0929,
'cuft_to_cum': 0.0283
}
リソース
- Dynamo 入門: https://primer.dynamobim.org
- Revit API ドキュメント: https://www.revitapidocs.com
- DDC ウェブサイト: https://datadrivenconstruction.io
次のステップ
- IFC エクスポートについては
ifc-data-extractionを参照してください - 高度な数量レポートについては
qto-reportを参照してください - 外部連携については
n8n-workflow-automationを参照してください
コメント
Markdown 対応