mcpField
B
bim-visual-programming-automation

bim-visual-programming-automation

github.com/datadrivenconstructionデータ・データベース375114 回インストール1 週間前に更新
リポジトリ

bim-visual-programming-automation について

Autodesk Revit と Dynamo の API を使って BIM ワークフローを自動化するスキルです。ビジュアルプログラミングのスクリプトと Python ノードで、要素データ、変更、集計表、外部データ連携、数量拾いを扱います。

主な機能

  1. 01要素データの抽出
  2. 02要素の一括変更
  3. 03集計表の生成
  4. 04パラメーター管理
  5. 05データのインポートとエクスポート
  6. 06数量拾いの自動化

活用シーン

  1. 01壁データの Excel 出力
  2. 02Revit パラメーターの一括更新
  3. 03カスタム集計表の作成
  4. 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
}

リソース

次のステップ

  • IFC エクスポートについては ifc-data-extraction を参照してください
  • 高度な数量レポートについては qto-report を参照してください
  • 外部連携については n8n-workflow-automation を参照してください

コメント