我正在创建一个 python 脚本,在 Revit 的 RevitPythonShell 2024.0.0.0 加载项中运行,它将查找不同 Revit 工作集中元素的重复族/类型名称,执行重命名功能并报告结果。它无法执行此操作,因为脚本无法验证 Revit 项目是否确实打开以执行任何任务(尽管其中一个明显是:具有超过 16,000 个 Revit 元素的工作共享 Revit 模型)提供以下错误:
当前没有文档打开或文档已被处置
然后中止。
下面是逻辑路径和当前脚本:
逻辑路径:
第1步:引用Revit API并检查项目是否打开。显示确认对话框。
第 2 步:按工作集编制族及其类型列表。
第 3 步:比较每个工作集中的族及其类型。
第 4 步:识别重复项并将其显示在对话框中。
步骤 5:通过将工作集名称附加到族名称来重命名重复的族。
第 6 步:根据重命名过程显示成功或失败消息。
第七步:将报告写入指定路径。
脚本如下:
import clr
import os
clr.AddReference('RevitAPI')
clr.AddReference('RevitServices')
clr.AddReference('RevitAPIUI')
clr.AddReference('System')
from Autodesk.Revit.DB import FilteredElementCollector, BuiltInParameter, Family, Transaction
from Autodesk.Revit.UI import TaskDialog, TaskDialogCommonButtons, TaskDialogResult
from RevitServices.Persistence import DocumentManager
from RevitServices.Transactions import TransactionManager
def main():
doc = DocumentManager.Instance.CurrentDBDocument
# Check if the document is valid
if doc is None or doc.IsDisposed:
TaskDialog.Show("Error", "No document is currently open or the document is disposed.")
return
filename = doc.PathName
if filename == "":
TaskDialog.Show("Error", "No document is currently open.")
return
result = TaskDialog.Show("Confirm", f"Current Project: {filename}\n\nDo you want to proceed?", TaskDialogCommonButtons.Yes | TaskDialogCommonButtons.No)
if result == TaskDialogResult.No:
return
# Create a dictionary to store families and their types by workset
workset_dict = {}
# Create a list to store the report data
report_data = []
# Get all families in the document
collector = FilteredElementCollector(doc).OfClass(Family)
for family in collector:
# Get the workset of the family
workset_param = family.get_Parameter(BuiltInParameter.ELEM_PARTITION_PARAM)
if workset_param:
workset_name = workset_param.AsValueString()
# Initialize the workset dictionary if not already
if workset_name not in workset_dict:
workset_dict[workset_name] = {}
# Get all types of the family
symbols = family.GetFamilySymbolIds()
for symbol_id in symbols:
symbol = doc.GetElement(symbol_id)
family_name = family.Name
type_name = symbol.Name
# Store family and type in the dictionary
if family_name not in workset_dict[workset_name]:
workset_dict[workset_name][family_name] = []
workset_dict[workset_name][family_name].append(type_name)
# Find duplicates
duplicates = {}
for workset_name, families in workset_dict.items():
for family_name, types in families.items():
for other_workset_name, other_families in workset_dict.items():
if workset_name != other_workset_name and family_name in other_families:
if family_name not in duplicates:
duplicates[family_name] = {}
if workset_name not in duplicates[family_name]:
duplicates[family_name][workset_name] = []
if other_workset_name not in duplicates[family_name]:
duplicates[family_name][other_workset_name] = []
duplicates[family_name][workset_name] = types
duplicates[family_name][other_workset_name] = workset_dict[other_workset_name][family_name]
if not duplicates:
TaskDialog.Show("Info", "No duplicate families found.")
return
duplicate_list = ""
for family_name, worksets in duplicates.items():
duplicate_list += f"Family: {family_name}\n"
for workset_name, types in worksets.items():
type_list = ", ".join(types)
duplicate_list += f" Workset: {workset_name}, Types: {type_list}\n"
result = TaskDialog.Show("Duplicates Found", f"Duplicate Families and Types:\n{duplicate_list}\n\nDo you want to proceed?", TaskDialogCommonButtons.Yes | TaskDialogCommonButtons.No)
if result == TaskDialogResult.No:
return
# Rename duplicates
rename_success = True
TransactionManager.Instance.EnsureInTransaction(doc)
try:
for family_name, worksets in duplicates.items():
for workset_name in worksets:
for family in FilteredElementCollector(doc).OfClass(Family):
if family.Name == family_name:
new_family_name = f"{workset_name}_{family_name}"
family.Name = new_family_name
report_data.append([workset_name, family_name, new_family_name])
TransactionManager.Instance.TransactionTaskDone()
except Exception as e:
TransactionManager.Instance.TransactionTaskDone()
rename_success = False
TaskDialog.Show("Error", str(e))
if rename_success:
TaskDialog.Show("Success", "Success!")
else:
TaskDialog.Show("Error", "Unable to complete task.")
return
# Write report
username = os.getlogin()
report_path = fr"C:\Users\{username}\Desktop\TWT\Duplicate_Family_Rename_Report.txt"
with open(report_path, 'w') as report_file:
report_file.write("Workset,Original Name,New Name\n")
for data in report_data:
report_file.write(f"{data[0]},{data[1]},{data[2]}\n")
TaskDialog.Show("Revit", f"Report saved to: {report_path}")
main()
我还尝试用另一个版本的代码替换前端代码,该版本执行更简单的重命名任务(不完全是我想要的,因此是上面的增强版本)并且最初是成功的。
脚本前端替换(包括整个新脚本):
import clr
clr.AddReference('RevitAPI')
clr.AddReference('RevitServices')
from Autodesk.Revit.DB import *
from RevitServices.Persistence import DocumentManager
from RevitServices.Transactions import TransactionManager**
# Get the current Revit document
doc = DocumentManager.Instance.CurrentDBDocument
# Check if the document is valid
doc_status_message = "Document is None or Disposed"
if doc is not None and not doc.IsDisposed:
doc_status_message = f"Document Title: {doc.Title}"
# Show a message box with the document status
TaskDialog.Show("Debug Info", doc_status_message)
# Proceed only if the document is valid
if doc is None or doc.IsDisposed:
TaskDialog.Show("Error", "No document is currently open or the document is disposed.")
else:
# Create a dictionary to store families and types by workset
workset_dict = {}
# Create a list to store the report data
report_data = []
# Get all families in the document
collector = FilteredElementCollector(doc).OfClass(Family)
for family in collector:
# Get the workset of the family
workset_param = family.get_Parameter(BuiltInParameter.ELEM_PARTITION_PARAM)
if workset_param:
workset_name = workset_param.AsValueString()
# Initialize the workset dictionary if not already
if workset_name not in workset_dict:
workset_dict[workset_name] = {}
# Get all types of the family
symbols = family.GetFamilySymbolIds()
for symbol_id in symbols:
symbol = doc.GetElement(symbol_id)
family_name = family.Name
type_name = symbol.Name
# Store family and type in the dictionary
if family_name not in workset_dict[workset_name]:
workset_dict[workset_name][family_name] = []
workset_dict[workset_name][family_name].append(type_name)
# Function to rename families and types
def rename_family_and_types(family, new_family_name, doc, workset_name, original_name):
t = Transaction(doc, "Rename Family and Types")
t.Start()
try:
family.Name = new_family_name
symbols = family.GetFamilySymbolIds()
for symbol_id in symbols:
symbol = doc.GetElement(symbol_id)
symbol.Name = new_family_name + "_" + symbol.Name
t.Commit()
# Add to the report data
report_data.append([workset_name, original_name, new_family_name])
except Exception as e:
t.RollBack()
TaskDialog.Show("Error", str(e))
# Iterate over the workset dictionary to check for duplicate names
for workset_name, families in workset_dict.items():
for family_name, types in families.items():
for other_workset_name, other_families in workset_dict.items():
if workset_name != other_workset_name and family_name in other_families:
# Rename the family and types with workset prefix
collector = FilteredElementCollector(doc).OfClass(Family)
for family in collector:
if family.Name == family_name:
new_family_name = f"{workset_name}_{family_name}"
rename_family_and_types(family, new_family_name, doc, workset_name, family_name)
# Specify the report file path
report_path = r"C:\Users\nwakeman\OneDrive - Wade Trim\Desktop\TWT\Family_Rename_Report.txt"
# Create the report file
with open(report_path, 'w') as report_file:
report_file.write("Workset\tOriginal Name\tNew Name\n")
for data in report_data:
report_file.write(f"{data[0]}\t{data[1]}\t{data[2]}\n")
TaskDialog.Show("Revit", f"Renaming of Families and Types based on Worksets is complete.\nReport saved to: {report_path}")`
确实承认相同的开放 Revit 项目的原始脚本 - 供参考:
`import clr
clr.AddReference("RevitAPI")
clr.AddReference("RevitServices")
clr.AddReference("RevitAPIUI")
from Autodesk.Revit.DB import *
from Autodesk.Revit.UI import *
from RevitServices.Persistence import DocumentManager
from RevitServices.Transactions import TransactionManager
import os
# Get the current document
doc = DocumentManager.Instance.CurrentDBDocument
# Create a dictionary to store families and types by workset
workset_dict = {}
# Create a list to store the report data
report_data = []
# Get all families in the document
collector = FilteredElementCollector(doc).OfClass(Family)
for family in collector:
# Get the workset of the family
workset_param = family.get_Parameter(BuiltInParameter.ELEM_PARTITION_PARAM)
if workset_param:
workset_name = workset_param.AsValueString()
# Initialize the workset dictionary if not already
if workset_name not in workset_dict:
workset_dict[workset_name] = {}
# Get all types of the family
symbols = family.GetFamilySymbolIds()
for symbol_id in symbols:
symbol = doc.GetElement(symbol_id)
family_name = family.Name
type_name = symbol.Name
# Store family and type in the dictionary
if family_name not in workset_dict[workset_name]:
workset_dict[workset_name][family_name] = []
workset_dict[workset_name][family_name].append(type_name)
# Function to rename families and types
def rename_family_and_types(family, new_family_name, doc, workset_name, original_name):
TransactionManager.Instance.EnsureInTransaction(doc)
family.Name = new_family_name
symbols = family.GetFamilySymbolIds()
for symbol_id in symbols:
symbol = doc.GetElement(symbol_id)
symbol.Name = new_family_name + "_" + symbol.Name
TransactionManager.Instance.TransactionTaskDone()
# Add to the report data
report_data.append([workset_name, original_name, new_family_name])
# Iterate over the workset dictionary to check for duplicate names
for workset_name, families in workset_dict.items():
for family_name, types in families.items():
for other_workset_name, other_families in workset_dict.items():
if workset_name != other_workset_name and family_name in other_families:
# Rename the family and types with workset prefix
collector = FilteredElementCollector(doc).OfClass(Family)
for family in collector:
if family.Name == family_name:
new_family_name = f"{workset_name}_{family_name}"
rename_family_and_types(family, new_family_name, doc, workset_name, family_name)
# Specify the report file path
report_path = r"C:\Users\nwakeman\OneDrive - Wade Trim\Desktop\TWT\Family_Rename_Report.txt"
# Create the report file
with open(report_path, 'w') as report_file:
report_file.write("Workset\tOriginal Name\tNew Name\n")
for data in report_data:
report_file.write(f"{data[0]}\t{data[1]}\t{data[2]}\n")
TaskDialog.Show("Revit", f"Renaming of Families and Types based on Worksets is complete.\nReport saved to: {report_path}")
很棒的剧本创意。
你从哪里得到这些最初的定义?我以前没听说过
RevitServices.Persistence
或 RevitServices.Transactions
- 它们听起来真的很有趣。
如果我使用一组通用的初始定义,我就可以运行你的脚本:
import clr
import os
clr.AddReference('RevitAPI')
clr.AddReference('RevitAPIUI')
from Autodesk.Revit.DB import *
from Autodesk.Revit.UI import *
doc = __revit__.ActiveUIDocument.Document
现在
doc
可以按预期工作
我还遇到了一些其他错误:
symbol.Name
需要是 Element.Name.__get__(symbol)
(奇怪的是,family.Name
工作得很好 - 需要将 Python 映射到网络)
让我们知道您的进展如何!