使用python在revit中创建和分配子类别

Lue*_*erJ 5 python revit revit-api revitpythonshell

对于熟悉Revit API和python的一些人,我有一个问题:

我一直在使用dynamo中的spring nodes包来创建一个相当大的自由对象系列,每个对象都在它们自己的系列中.FamilyInstance.ByGeometry的工作方式,它采用实体列表,并使用模板系列文件为每个实体创建一个族实例.结果非常好.(可以在这里找到spring节点:https://github.com/dimven/SpringNodes)

但是,缺点是现在我有大约200个单独的实例,所以对每个实例进行更改是相当痛苦的.我一开始认为可以使用dynamo来创建一个新的子类别,并将每个族实例中的实体设置为这个新的子类别.不幸的是,我意识到这是不可能的,因为dynamo不能同时在两个不同的Revit环境中打开(我正在工作的项目和该系列的每个实例).这让我想看看我是否可以使用python来做到这一点.

我在rhino中使用了python并且相处得很好,但我仍在学习Revit API.但基本上我的想法是:1.在Revit项目环境中选择一系列族实例2.遍历每个实例3.将其保存到指定位置4.在每个族实例中创建一个新的子类别(子类别将是对于所有选定的族实例都相同)5.在实例中选择每个实体中的实体6.将实体设置为此新创建的子类别7.关闭族实例并保存

我的问题是,这听起来像是根据您对Revit API的了解可以实现的吗?

非常感谢您的时间和建议.


更新:

我在revit api中找到了一个描述我要做的事情的部分:http://help.autodesk.com/view/RVT/2015/ENU/?guid = GUID-FBF9B994-ADCB-4679-B50B -2E9A1E09AA48

我已经第一次将它插入到dynamo节点的python代码中.其余的代码工作正常,除了我添加的新部分(见下文).请原谅变量,我只是保持我正在黑客攻击的代码原作者的逻辑:

(注意:变量进来是在数组中)

#set subcategory    
try:
     #create new sucategory
     fam_subcat = famdoc.Settings.Categories.NewSubcategory(fam_cat, get_Item(subcat1.Name))                

     #assign the mataterial(fam_mat.Id) to the subcategory
     fam_subcat.Material = famdoc.GetElement(fam_mat.Id)

     #assign the subcategory to the element (s2)
     s2.Subcategory = fam_subcat
except: pass
Run Code Online (Sandbox Code Playgroud)

任何有关此部分代码的帮助或建议都将非常感谢.


更新:请参阅下面的完整代码,了解相关部分的上下文:

#Copyright(c) 2015, Dimitar Venkov
# @5devene, dimitar.ven@gmail.com

import clr
import System
from System.Collections.Generic import *

pf_path = System.Environment.GetFolderPath(System.Environment.SpecialFolder.ProgramFilesX86)
import sys
sys.path.append("%s\IronPython 2.7\Lib" %pf_path)
import traceback

clr.AddReference('ProtoGeometry')
from Autodesk.DesignScript.Geometry import *

clr.AddReference("RevitServices")
import RevitServices
from RevitServices.Persistence import DocumentManager
from RevitServices.Transactions import TransactionManager
doc = DocumentManager.Instance.CurrentDBDocument
app = DocumentManager.Instance.CurrentUIApplication.Application

clr.AddReference("RevitAPI")
from Autodesk.Revit.DB import *
from Autodesk.Revit.DB.Structure import StructuralType

clr.AddReference("RevitNodes")
import Revit
clr.ImportExtensions(Revit.Elements)
clr.ImportExtensions(Revit.GeometryConversion)

def tolist(obj1):
    if hasattr(obj1,"__iter__"): return obj1
    else: return [obj1]

def output1(l1):
    if len(l1) == 1: return l1[0]
    else: return l1

def PadLists(lists):
    len1 = max([len(l) for l in lists])
    for i in xrange(len(lists)):
        if len(lists[i]) == len1:
            continue
        else:
            len2 = len1 - len(lists[i])
            for j in xrange(len2):
                lists[i].append(lists[i][-1])
    return lists

class FamOpt1(IFamilyLoadOptions):
    def __init__(self):
        pass
    def OnFamilyFound(self,familyInUse, overwriteParameterValues):
        return True
    def OnSharedFamilyFound(self,familyInUse, source, overwriteParameterValues):
        return True

geom = tolist(IN[0])
fam_path = IN[1]
names = tolist(IN[2])
category = tolist(IN[3])
material = tolist(IN[4])
isVoid = tolist(IN[5])
subcategory = tolist(IN[6])

isRvt2014 = False
if app.VersionName == "Autodesk Revit 2014": isRvt2014 = True
units = doc.GetUnits().GetFormatOptions(UnitType.UT_Length).DisplayUnits
factor = UnitUtils.ConvertToInternalUnits(1,units)
acceptable_views = ["ThreeD", "FloorPlan", "EngineeringPlan", "CeilingPlan", "Elevation", "Section"]
origin = XYZ(0,0,0)
str_typ = StructuralType.NonStructural

def NewForm_background(s1, name1, cat1, isVoid1, mat1, subcat1):
    t1 = TransactionManager.Instance
    TransactionManager.ForceCloseTransaction(t1)
    famdoc = doc.Application.NewFamilyDocument(fam_path)
    message = None
    temp_path = System.IO.Path.GetTempPath()
    sat_path = "%s%s.sat" % (temp_path, name1)
    try:
        if factor != 1:
            s1 = s1.Scale(factor)
        sat1 = Geometry.ExportToSAT(s1, sat_path)
        satOpt = SATImportOptions()
        satOpt.Placement = ImportPlacement.Origin
        satOpt.Unit = ImportUnit.Foot
        view_fec = FilteredElementCollector(famdoc).OfClass(View)
        view1 = None
        for v in view_fec:
            if str(v.ViewType) in acceptable_views:
                view1 = v
                break
        t1.EnsureInTransaction(famdoc)
        satId = famdoc.Import(sat1, satOpt, view1)
        opt1 = Options()
        opt1.ComputeReferences = True
        el1 = famdoc.GetElement(satId)
        geom1 = el1.get_Geometry(opt1)
        enum = geom1.GetEnumerator()
        enum.MoveNext()
        geom2 = enum.Current.GetInstanceGeometry()
        enum2 = geom2.GetEnumerator()
        enum2.MoveNext()
        s1 = enum2.Current
        famdoc.Delete(satId)
        TransactionManager.ForceCloseTransaction(t1)
        System.IO.File.Delete(sat_path)
    except:
        message = traceback.format_exc()
        pass
    if message == None:
        try:
            save_path = "%s%s.rfa" % (temp_path, name1)
            SaveAsOpt = SaveAsOptions()
            SaveAsOpt.OverwriteExistingFile = True
            t1.EnsureInTransaction(famdoc)
            #set the category
            try:
                fam_cat = famdoc.Settings.Categories.get_Item(cat1.Name)
                famdoc.OwnerFamily.FamilyCategory = fam_cat
            except: pass
            s2 = FreeFormElement.Create(famdoc,s1)
            if isVoid1:
                void_par = s2.get_Parameter("Solid/Void")
                void_par.Set(1)
                void_par2 = famdoc.OwnerFamily.get_Parameter("Cut with Voids When Loaded")
                void_par2.Set(1)
            else: #voids do not have a material value
                try:
                    mat_fec = FilteredElementCollector(famdoc).OfClass(Material)
                    for m in mat_fec:
                        if m.Name == mat1:
                            fam_mat = m
                            break
                    mat_par = s2.get_Parameter("Material")
                    mat_par.Set(fam_mat.Id)
                except: pass
            #set subcategory    
            try:
                #create new sucategory
                fam_subcat = document.Settings.Categories.NewSubcategory(document.OwnerFamily.FamilyCategory, get_Item(subcat1.Name))               

                #assign the mataterial(fam_mat.Id) to the subcategory
                fam_subcat.Material = famdoc.GetElement(fam_mat.Id)

                #assign the subcategory to the element (s2)
                s2.Subcategory = fam_subcat
            except: pass

            TransactionManager.ForceCloseTransaction(t1)
            famdoc.SaveAs(save_path, SaveAsOpt)
            family1 =  famdoc.LoadFamily(doc, FamOpt1())
            famdoc.Close(False)
            System.IO.File.Delete(save_path)
            symbols = family1.Symbols.GetEnumerator()
            symbols.MoveNext()
            symbol1 = symbols.Current
            t1.EnsureInTransaction(doc)
            if not symbol1.IsActive: symbol1.Activate()
            inst1 = doc.Create.NewFamilyInstance(origin, symbol1, str_typ)
            TransactionManager.ForceCloseTransaction(t1)
            return inst1.ToDSType(False), family1.ToDSType(False)
        except:
            message = traceback.format_exc()
            return message
    else:
        return message

def NewForm_background_R16(s1, name1, cat1, isVoid1, mat1, subcat1):
    t1 = TransactionManager.Instance
    TransactionManager.ForceCloseTransaction(t1)
    famdoc = doc.Application.NewFamilyDocument(fam_path)
    message = None
    temp_path = System.IO.Path.GetTempPath()
    sat_path = "%s%s.sat" % (temp_path, name1)
    try:
        if factor != 1:
            s1 = s1.Scale(factor)
        sat1 = Geometry.ExportToSAT(s1, sat_path)
        satOpt = SATImportOptions()
        satOpt.Placement = ImportPlacement.Origin
        satOpt.Unit = ImportUnit.Foot
        view_fec = FilteredElementCollector(famdoc).OfClass(View)
        view1 = None
        for v in view_fec:
            if str(v.ViewType) in acceptable_views:
                view1 = v
                break
        t1.EnsureInTransaction(famdoc)
        satId = famdoc.Import(sat1, satOpt, view1)
        opt1 = Options()
        opt1.ComputeReferences = True
        el1 = famdoc.GetElement(satId)
        geom1 = el1.get_Geometry(opt1)
        enum = geom1.GetEnumerator()
        enum.MoveNext()
        geom2 = enum.Current.GetInstanceGeometry()
        enum2 = geom2.GetEnumerator()
        enum2.MoveNext()
        s1 = enum2.Current
        famdoc.Delete(satId)
        TransactionManager.ForceCloseTransaction(t1)
        System.IO.File.Delete(sat_path)
    except:
        message = traceback.format_exc()
        pass
    if message == None:
        try:
            save_path = "%s%s.rfa" % (temp_path, name1)
            SaveAsOpt = SaveAsOptions()
            SaveAsOpt.OverwriteExistingFile = True
            t1.EnsureInTransaction(famdoc)
            #set the category
            try:
                fam_cat = famdoc.Settings.Categories.get_Item(cat1.Name)
                famdoc.OwnerFamily.FamilyCategory = fam_cat
            except: pass
            s2 = FreeFormElement.Create(famdoc,s1)
            if isVoid1:
                void_par = s2.LookupParameter("Solid/Void")
                void_par.Set(1)
                void_par2 = famdoc.OwnerFamily.LookupParameter("Cut with Voids When Loaded")
                void_par2.Set(1)
            else: #voids do not have a material value
                try:
                    mat_fec = FilteredElementCollector(famdoc).OfClass(Material)
                    for m in mat_fec:
                        if m.Name == mat1:
                            fam_mat = m
                            break
                    mat_par = s2.LookupParameter("Material")
                    mat_par.Set(fam_mat.Id)
                except: pass

            #apply same subcategory code as before
            #set subcategory    
            try:
                #create new sucategory
                fam_subcat = famdoc.Settings.Categories.NewSubcategory(fam_cat, get_Item(subcat1.Name))             

                #assign the mataterial(fam_mat.Id) to the subcategory
                fam_subcat.Material = famdoc.GetElement(fam_mat.Id)

                #assign the subcategory to the element (s2)
                s2.Subcategory = fam_subcat
            except: pass


            TransactionManager.ForceCloseTransaction(t1)
            famdoc.SaveAs(save_path, SaveAsOpt)
            family1 =  famdoc.LoadFamily(doc, FamOpt1())
            famdoc.Close(False)
            System.IO.File.Delete(save_path)
            symbols = family1.GetFamilySymbolIds().GetEnumerator()
            symbols.MoveNext()
            symbol1 = doc.GetElement(symbols.Current)
            t1.EnsureInTransaction(doc)
            if not symbol1.IsActive: symbol1.Activate()
            inst1 = doc.Create.NewFamilyInstance(origin, symbol1, str_typ)
            TransactionManager.ForceCloseTransaction(t1)
            return inst1.ToDSType(False), family1.ToDSType(False)
        except:
            message = traceback.format_exc()
            return message
    else:
        return message

if len(geom) == len(names) == len(category) == len(isVoid) == len(material) == len(subcategory):
    if isRvt2014:
        OUT = output1(map(NewForm_background, geom, names, category, isVoid, material, subcategory))
    else:
        OUT = output1(map(NewForm_background_R16, geom, names, category, isVoid, material, subcategory))
elif len(geom) == len(names):
    padded = PadLists((geom, category, isVoid, material, subcategory))
    p_category = padded[1]
    p_isVoid = padded[2]
    p_material = padded[3]
    p_subcategory = padded [4]
    if isRvt2014:
        OUT = output1(map(NewForm_background, geom, names, p_category, p_isVoid, p_material, p_subcategory))
    else:
        OUT = output1(map(NewForm_background_R16, geom, names, p_category, p_isVoid, p_material, subcategory))
else: OUT = "Make sure that each geometry\nobject has a unique family name."
Run Code Online (Sandbox Code Playgroud)

更新:

能够让它运作:

    try:
        #create new sucategory
        fam_subcat = famdoc.Settings.Categories.NewSubcategory(famdoc.OwnerFamily.FamilyCategory, subcat1)          

        #assign the mataterial(fam_mat.Id) to the subcategory
        #fam_subcat.Material = famdoc.GetElement(fam_mat.Id)

        #assign the subcategory to the element (s2)
        s2.Subcategory = fam_subcat
    except: pass
Run Code Online (Sandbox Code Playgroud)

Jer*_*mik 1

正如我在每封电子邮件中回答您最初的询问一样,您的目标在 Revit API 中对我来说听起来完全可行。恭喜您已经取得了如此大的成就。查看上面引用的 Revit API 帮助文件和开发人员指南的链接,似乎在定义族时必须在族文档中执行代码。您尝试执行它的上下文尚不清楚。您是否使用过EditFamily打开族定义文档?您在什么上下文中执行?