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. 02批量更新 Revit 参数
  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-data-extraction,了解 IFC 导出
  • 查看 qto-report,了解高级工程量报告
  • 查看 n8n-workflow-automation,了解外部集成

评论

支持 Markdown